IOC控制反转

    科技2025-02-17  15

    IOC容器(控制反转)

    1. IOC底层原理

    xml解析工厂模式反射

    概念和原理

    什么是IOC

    控制反转,把对象的创建和对象之间的调用过程,交给Spring进行管理使用IOC目的:为了耦合度降低做入门的案例就是IOC实现

    工厂模式

    目的:降低耦合度到最低限度

    IOC过程,进一步降低耦合度

    xml配置文件,配置创建的对象

    <bean id="dao" class="com.yang.UserDao"/>

    第二步 有service和dao类,创建工厂类

    class UserFactory{ public static UserDao getDao{ String classValue = class属性值;//1.xml解析得到 //2.通过反射得到对象 Class clazz = Class.forName(classValue); return (UserDao)clazz.newInstance(); } }

    2. IOC接口(BeanFactory)

    IOC思想基于IOC容器完成,IOC容器底层就是对象工厂Spring提供IOC容器实现的两种方式:(两个接口) BeanFactory:IOC容器基本实现,是Spring内部使用的接口,不提供给开发人员使用,加载配置文件的时候不会创建对象,获取或使用时才去创建对象。ApplicationContext: BeanFactory接口的子接口,提供更强大的功能。在加载配置文件的时候就会把配置对象进行创建。 ApplicationContext接口有实现类

    3. IOC操作,Bean管理(基于xml)

    什么是Bean管理?包括创建对象与注入属性

    Spring创建对象Spring注入属性

    3.1 基于xml方式创建对象

    <bean id="user" class="com.yang.User"/> 在spring配置文件中,使用bean标签,标签中添加上对应属性,就可以实现对象创建在bean标签中有很多属性,介绍常用属性 id属性:唯一标识class属性:类的全路径 创建对象的时候默认执行无参的构造方法

    3.2 基于xml方式注入属性

    DI:依赖注入,就是注入属性,DI是IOC的一种实现方式

    第一种注入方式,使用set注入

    实体类创建

    package com.yang; public class Book { private String bname; private String author; //set方法注入 public void setBname(String bname, String author) { this.bname = bname; this.author = author; } public Book() { } public void setBname(String bname) { this.bname = bname; } public void setAuthor(String author) { this.author = author; } //有参构造注入 public Book(String bname) { this.bname = bname; } }

    bean文件配置

    <!-- set方法注入属性--> <bean id="book" class="com.yang.Book"> <!-- 使用property完成属性注入 name属性代表字段名称 value为注入的值 --> <property name="bname" value="天龙八部"/> <property name="author" value="杨剑"/> </bean>

    第二种注入方式,使用有参构造注入

    创建类,定义属性,创建构造方法

    public class Orders { private String name; private String address; public Orders(String name, String address) { this.name = name; this.address = address; } }

    在spring配置文件中配置

    <bean id="orders" class="com.yang.Orders"> <constructor-arg name="name" value="电脑"/> <constructor-arg name="address" value="中国"/> </bean>

    第三种注入方式:p名称空间注入(了解即可)

    使用p名称空间注入可以简化基于xml的配置方式

    在配置文件中添加p名称空间

    xmlns:p="http://www.springframework.org/schema/p"

    进行属性注入,在bean标签里进行操作

    <bean id="book" class="com.yang.Book" p:bname="名字" p:author="作者"/>

    IOC操作Bean管理(XML注入其他类型属性)

    字面量注入属性-外部bean注入属性-内部bean级联赋值

    字面量

    空值

    <property name="author"> <null/> </property>

    属性值包含特殊符号

    转义:> <

    CDATE

    <property name="author"> <value> <![CDATA[ <<南京>> ]]> </value> </property>

    注入属性-外部bean

    创建两个类service和dao类

    在service调用dao里面的方法

    在Spring配置文件中进行配置

    <!-- service和dao对象的创建--> <bean id="userService" class="com.yang.service.UserService"> <!-- 注入userDao对象 name:属性值:类里面的属性名称 --> <property name="userDao" ref="userDaoImpl"/> </bean> <bean id="userDaoImpl" class="com.yang.dao.UserDaoImpl"/>

    注入属性-内部bean和级联赋值

    一对多关系:部门和员工

    一个部门有多个员工,一个员工属于某一个部门

    在实体类中体现一对多关系

    员工表示所属部门,用对象表示

    //部门类 public class Department { private String dName; public void setdName(String dName) { this.dName = dName; } } //员工类 public class Emp { private String ename; private String gender; //员工属于某一个部门,使用对象形式表示 private Department department; public void setEname(String ename) { this.ename = ename; } public void setGender(String gender) { this.gender = gender; } }

    在spring配置文件中进行相关配置

    <!--内部bean--> <bean id="emp" class="com.yang.bean.Emp"> <!-- 先设置两个普通属性--> <property name="ename" value="ya"/> <property name="gender" value=""/> <!-- 对象类型属性--> <property name="department"> <bean class="com.yang.bean.Department"> <property name="dName" value="公司"/> </bean> </property> </bean>

    注入属性:级联赋值

    第一种方式

    <bean id="emp" class="com.yang.bean.Emp"> <!-- 先设置两个普通属性--> <property name="ename" value="ya"/> <property name="gender" value=""/> <!-- 对象类型属性--> <!-- 级联赋值--> <property name="department" ref="deparment"/> </bean> <bean id="deparment" class="com.yang.bean.Department"> <property name="dName" value="财务部"/> </bean> 第二种方式,需要生成deparment的get方法 <bean id="emp" class="com.yang.bean.Emp"> <!-- 先设置两个普通属性--> <property name="ename" value="ya"/> <property name="gender" value=""/> <!-- 对象类型属性--> <!-- 级联赋值--> <property name="department" ref="department"/> <property name="department.dName" value="cai"/> </bean> <bean id="department" class="com.yang.bean.Department"> <property name="dName" value="财务部"/> </bean>

    xml注入集合属性

    注入数组类型属性注入List集合注入Map集合类型的属性

    创建类,定义数组, list,map,set集合属性,生成对应的set方法

    在spring配置文件中配置

    <bean id="student" class="com.yang.collectionType.Student"> <!-- 数组类型--> <property name="courses"> <array> <value>java</value> <value>数据库</value> </array> </property> <!-- list类型--> <property name="list"> <list> <value>张三</value> <value>小三</value> </list> </property> <!-- Map类型--> <property name="maps"> <map> <entry key="Java" value="java"/> <entry key="PHP" value="php"/> </map> </property> <!-- set--> <property name="set"> <set> <value>123</value> <value>mysql</value> </set> </property> </bean>

    在集合里设置对象类型值

    <property name="courseList"> <list> <ref bean="course1"/> <ref bean="course2"/> </list> </property> <bean id="course1" class="com.yang.collectionType.Course"> <property name="cname" value="Spring5框架"/> </bean> <bean id="course2" class="com.yang.collectionType.Course"> <property name="cname" value="MyBatis框架"/> </bean>

    把集合注入部分提取出来

    在Spring配置文件中引入名称空间 util

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd ">

    使用util标签提取

    <util:list id="bookList"> <value>三国</value> <value>水浒</value> </util:list> <bean id="book" class="com.yang.collectionType.Book"> <property name="list" ref="bookList"/> </bean>

    IOC操作Bean管理(FactoryBean)

    Spring有两种类型的Bean,一种普通Bean,另一种:工厂Bean(FactoryBean)

    普通Bean:在配置文件中定义的Bean类型就是你的返回类型

    工厂Bean:在配置文件中定义的Bean类型可以和返回类型不一样

    第一步:让这个类作为工厂Bean,实现接口FactoryBean

    <bean id="myBean" class="com.yang.factorybean.MyBean"> </bean>

    第二步:实现接口里的方法,在实现的方法中定义返回的bean类型

    public class MyBean implements FactoryBean<Course> { //定义返回Bean public Course getObject() throws Exception { Course course = new Course(); course.setCname("abc"); return course; } public Class<?> getObjectType() { return null; } public boolean isSingleton() { return false; } }

    IOC操作Bean管理(Bean作用域)

    在Spring里面,设置创建bean实例是单实例还是多实例

    在Spring里面,默认情况下,bean是单实例对象

    如何设置单实例还是多实例

    spring配置文件中bean标签里有属性(scope)用于设置单实例还是多实例

    scope属性值

    第一个值 默认值,singleton,表示单实例对象

    第二个值 prototype,多实例对象

    scope和prototype的区别

    第一:singleton:单实例

    ​ prototype:多实例

    第二:设置scope为singleton的时候,加载配置文件的时候就会创建一个单实例对象

    ​ 设置scope值是prototype的时候,不是加载配置文件时创建对象,在调用getBean方法的时候去创建多实例对象

    还有request,session,一般不用,了解即可

    生命周期: 从对象创建到对象销毁的的过程

    bean生命周期

    通过构造器创建bean实例(无参构造)为bean的属性设置值和对其他bean的引用(调用set方法)调用bean的初始化的方法(需要进行配置)bean可以使用了(对象获取到了)当容器在关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)

    演示bean的生命周期

    package com.yang.bean; public class Orders { private String oname; public void setOname(String oname) { this.oname = oname; System.out.println("第二部,调用set方法设置属性值"); } public Orders(){ System.out.println("第一步,无参构造创建bean实例"); } //创建执行的初始化方法 public void initMethod(){ System.out.println("第三步,执行初始化的方法"); } //创建销毁的方法 public void destroyMethod(){ System.out.println("第五步,执行销毁的方法"); } } public void test2(){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml"); Orders orders = context.getBean("orders", Orders.class); System.out.println("第四部,获取创建bean实例的对象"); System.out.println(orders); //手动销毁bean实例 context.close(); }

    bean的后置处理器,bean生命周期变为七步

    bean生命周期

    通过构造器创建bean实例(无参构造)为bean的属性设置值和对其他bean的引用(调用set方法)把bean实例传给bean后置处理器的方法postProcessBeforeInitialization调用bean的初始化的方法(需要进行配置)把bean实例传给bean后置处理器的方法postProcessAfterInitializationbean可以使用了(对象获取到了)当容器在关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)

    添加后置处理器效果

    创建类,实现接口BeanPostProcessor,创建后置处理器

    package com.yang.bean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPost implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之前执行的方法"); return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之后执行的方法"); return bean; } }

    在bean中配置,自动为所有bean加上

    <bean id="myBeanPost" class="com.yang.bean.MyBeanPost"/>

    xml自动装配

    什么是自动装配?

    根据指定装配规则(属性名称或属性类型),Spring自动将匹配的属性值进行注入

    演示自动装配过程

    根据属性名称进行自动注入 byName

    <bean id="emp" class="com.yang.autowire.Emp" autowire="byName"> <!-- <property name="dept" ref="dept"/>--> </bean> <bean id="dept" class="com.yang.autowire.Dept"/>

    根据属性类型进行自动注入 byType

    <bean id="emp" class="com.yang.autowire.Emp" autowire="byType"> <!-- <property name="dept" ref="dept"/>--> </bean> <bean id="dept" class="com.yang.autowire.Dept"/>

    外部属性文件

    直接配置数据库信息,配置druid连接池

    配置druid连接池

    引入druid连接池依赖

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean>

    引入外部属性文件配置数据库连接池

    创建外部属性文件,properties格式文件,写数据库信息

    prop.driverClass=com.mysql.jdbc.Driver prop.url=jdbc:mysql://localhost:3306/mybatis?useSSL=true prop.userName=root prop.password=123456

    把外部properties属性文件引入到Spring配置文件中

    引入context名称空间

    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    在spring配置文件中使用标签引入外部属性文件

    写入

    <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${prop.driverClass}"/> <property name="url" value="${prop.url}"/> <property name="username" value="${prop.userName}"/> <property name="password" value="${prop.password}"/> </bean>

    4. IOC操作,Bean管理(基于注解)

    什么是注解使用注解的目的:简化xml操作

    spring针对Bean管理中创建对象提供注解

    @Component

    @Service

    @Controller

    @Respository

    上面的四个注解功能是一样的,都可以用来创建bean实例

    基于注解方式实现对象的创建

    引入AOP依赖

    <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.9.RELEASE</version> </dependency>

    开启组件扫描

    <!-- 开启组件扫描 1.如果扫描多个包,多个包用逗号隔开 2.扫描上层目录 --> <context:component-scan base-package="com.yang"/>

    创建类,在类上面添加对象注解

    //在注解里的value属性值可以省略不写 //默认值是类的名称,把首字母小写 @Service(value = "userService") //<bean id="userService" class=""/> public class UserService { public void add() { System.out.println("service add.............."); } }

    开启组件扫描细节配置

    <!-- 示例1 use-default-filters="false" 表示现在不使用默认的filter,而是使用自己配置的filter context:include-filter:设置要扫描哪些内容 --> <context:component-scan base-package="com.yang" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <!-- 事例2: context:exclude-filter 设置哪些内容不进行扫描 --> <context:component-scan base-package="com.yang"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan>

    注解方式属性注入

    @Autowired:根据属性类型进行自动装配@Qualifier:根据属性名称进行注入@Resource:可以根据类型注入,也可以根据名称注入@Value:注入普通类型属性

    @Autowired

    把service和dao对象创建,在service和dao类添加创建对象的注解

    在service注入dao,在service类添加dao类型的属性,在属性上面使用注解

    //在注解里的value属性值可以省略不写 //默认值是类的名称,把首字母小写 @Service(value = "userService") //<bean id="userService" class=""/> public class UserService { //定义dao类型属性 //不需要添加set方法 //添加属性注解 @Autowired //根据类型进行注入 private UserDao userDao; public void add() { System.out.println("service add.............."); userDao.add(); } } @Repository public class UserDaoImpl implements UserDao{ public void add() { System.out.println("dao add...."); } }

    @Qualifier:根据属性名称进行注入

    这个@Qualifier注解的使用要和上面的@Autowired一起使用

    @Repository(value = "userDaoImpl1") public class UserDaoImpl implements UserDao{ public void add() { System.out.println("dao add...."); } } @Autowired //根据类型进行注入 @Qualifier(value = "userDaoImpl1") //根据名称及逆行注入

    @Resource:可以根据类型注入,也可以根据名称注入,包:javax.annotation.Resource

    @Service(value = "userService") //<bean id="userService" class=""/> public class UserService { //@Resource //根据类型进行注入 @Resource(name = "userDaoImpl1")//根据名称进行注入 private UserDao userDao; public void add() { System.out.println("service add.............."); userDao.add(); } }

    @Value:注入普通属性

    @Value(value = "yj") private String name;

    完全注解开发

    创建配置类,替代xml配置文件

    @Configuration //作为配置类 ,替代xml配置文件 @ComponentScan(basePackages = {"com.yang"}) public class SpringConfig { }

    测试类

    @Test public void test2(){ //加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService", UserService.class); userService.add(); }
    Processed: 0.020, SQL: 8