IOC的定义
IOC的全称叫Inversion Of Control, 也就是控制反转。它的核心思想是把对象的管理权限交给了容器。
应用程序如果需要使用某个对象的实例,那么直接从IOC容器里面去获取就可以了。
那么这种设计的好处在于降低了程序里面对象与对象之间的耦合性,使得程序的整个体系结构变得更加灵活。
Bean的声明方式
Spring里面提供了很多方式去声明一个Bean,比如说在XML配置文件里面。通过<bean>
的标签或者通过@Service注解
或者通过@Configuration配置类
里面通过@Bean注解
去声明等等。
那么Spring在启动的时候,会去解析这些bean,然后保存到IOC容器里面。
IOC的工作流程
1. IOC容器的初始化阶段
这个阶段主要是根据程序里面定义的XML或者注解等Bean的声明方式通过解析和加载后生成BeanDefinition,然后把BeanDefinition注册到IOC容器里面。
通过注解或者xml声明的bean都会解析得到一个BeanDefinition实体。这个实体里面会包含bean的一些定义和基本的一些属性。最后会把这个BeanDefinition保存到一个Map集合里面,从而去完成IOC的一个初始化。
IOC容器的作用就是对这些注册的Bean的定义信息进行处理和维护。它是IOC控制反转的一个核心。
2. 完成Bean初始化及依赖注入
这个阶段会做两个事情。
第一个是通过反射去针对没有设置lazy-init属性的单例bean进行初始化。
【补充】该句话的含义是在Spring容器中,如果一个单例(singleton)的bean没有设置lazy-init属性(懒加载),那么在容器启动时就会立即实例化该bean,并将其放入容器中。此时,如果我们使用反射技术获取该bean的实例对象,Spring容器会检测到该bean还没有完成初始化,会自动触发其初始化方法以完成实例化。因此,我们可以通过反射获取该单例bean的实例对象,并保证其已经完成了初始化。
第二个是完成Bean的依赖注入。
3. Bean的使用
通常我们会通过@Autowired
这样一个注解或者通过BeanFactory.getBean()
从IOC容器里面去获取一个指定的bean的实例。
另外针对设置了lazy-init属性以及非单例bean的一个实例化,是在每一次获取bean对象的时候,调用bean的初始化方法来完成实例化的。并且Spring IOC容器不会去管理这些Bean。
官网中的定义
IOC与大家熟知的依赖注入同理,这是一个通过依赖注入对象的过程,也就是说,它们所使用的对象,是通过构造函数参数、工厂方法的参数或者是从工厂方法的构造函数或返回值的对象实例设置的属性,然后容器在创建bean时注入这些需要的依赖。
这个过程相对普通创建对象的过程是反向的(因此称之为IoC),bean本身通过直接构造类来控制依赖关系的实例化或位置,或提供诸如服务定位器模式之类的机制。
如果这个过程比较难理解的话,那么可以想象自己找女朋友和婚介公司找女朋友的过程。如果这个过程能够想明白的话,那么我们现在回答上面的问题:
- 谁控制谁:在之前的编码过程中,都是需要什么对象自己去创建什么对象,由程序员自己来控制对象,而有了IOC容器之后,就变成由IOC容器来控制对象。
- 控制什么:在实现过程中所需要的对象及需要依赖的对象。
- 什么是反转:在没有IOC容器之前我们都是在对象中主动去创建依赖的对象,这是正转的,而有了IOC之后,依赖的对象直接由IOC容器创建后注入到对象中,由主动创建变成了被动接受,这是反转。
- 哪些方面被反转:依赖的对象, 把对象的管理权限交给了容器。
参考资料: