IoC(Inversion of Control,控制反转),也叫依赖注入(Dependency Injection),是一种决定容器如何装配组件的模式。使用 Spring 来实现 IoC,意味着将设计好的对象交给 Spring 容器控制,而不是直接在对象内部控制。控制反转不能很好地描述这个模式,依赖注入却能更好地描述它的特点,所以才经常看到这两个词一同出现。
只要遵循这种模式,按照一定规则,容器就能将组件组装起来。这里的容器就是用来创建组件并对它们进行管理的地方。它牵扯到组件如何定义、何时创建、何时销毁、它们互相之间是什么关系等,这些本该在组件内部管理的东西,被从组件中剥离了出来。组件之间的依赖关系原先是由组件自己定义的,并在其内部维护,而现在这些依赖被定义在容器中,由容器来统一管理,并据此将其依赖的内容注入组件中。
总结下,Spring IoC 容器的作用是将业务对象(也就是组件,Spring 中这些组件被称为 Bean)和关于组件的配置元数据(比如依赖关系)输入 Spring 容器中,容器就能组装出一个可用的系统。
Spring IoC 容器
Spring Framework 中,BeanFactory 是容器的基础接口,平时使用的各种容器都是它的实现。Spring 容器需要配置元数据和业务对象,在初始化容器时需要提供这些信息。早期元数据只能用 XML 配置,从 2.5 版本开始,官方提供了基于注解的配置和基于 Java 类的配置。
容器初始化
容器初始化的大致步骤如下,
1. 从 XML 文件、Java 类或其他地方加载配置元数据;
2. 通过 BeanFactoryPostProcessor 对配置元数据进行一轮处理;
3. 初始化 Bean 实例,并根据给定的依赖关系组装对象;
4. 通过 BeanPostProcessor 对 Bean 进行处理,期间还会触发 Bean 被构造后的回调方法。
在没有 IoC 容器时,对于普通 Java 类通常用 new 创建实例后直接调用方法,如下,
public class Hello {
public String hello() {
return "Hello World!";
}
}
public class SoraApplication {
public static void main(String[] args) {
Hello hello = new Hello();
System.out.println(hello.hello());
}
}
如果把实例交给 Spring 容器托管,可以把它配置到一个 XML 文件中,让容器来管理它的相关生命周期。随着工程复杂度的增加,IoC 托管 Bean 生命周期的优势就体现出来了。
package sora.example;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import sora.example.instances.Hello;
public class SoraApplication {
private BeanFactory beanFactory;
public SoraApplication() {
beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader =
new XmlBeanDefinitionReader((DefaultListableBeanFactory) beanFactory);
rea