IOC 容器的启动过程,启动过程分为两个步骤,第一个阶段是容器的启动阶段,第二个阶段是 Bean 实例化阶段。

判断spring容器是否启动完毕 spring容器启动顺序_判断spring容器是否启动完毕

注意:在 Spring 中,最基础的容器接口方法是由 BeanFactory 定义的,而 BeanFactory 的实现类采用的是 延迟加载,也就是说,容器启动时,只会进行第一个阶段的操作, 当需要某个类的实例时,才会进行第二个阶段的操作。而 ApplicationContext(另一个容器的实现类)在启动容器时就完成了所有初始化,这就需要更多的系统资源,我们需要根据不同的场景选择不同的容器实现类。

1.容器启动阶段

①加载配置

IOC 容器读取配置文件的接口为 BeanDefinitionReader,它会根据配置文件格式的不同给出不同的实现类,将配置文件中的内容读取并映射到 BeanDefinition 中,整个过程可以通过如下代码表示:

public static void main(String[] args){
    DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
    BeanFactory container = (BeanFactory)bindViaPropertiesFile(beanRegistry);
    FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
    newsProvider.getAndPersistNews();
}
public static BeanFactory bindViaPropertiesFile(BeanDefinitionRegistry registry){
    BeanDefinitionRegistry beanRegistry = <某个 BeanDefinitionRegistry 实现类,通常为 DefaultListableBeanFactory>;
    BeanDefinitionReader beanDefinitionReader = new BeanDefinitionReaderImpl(beanRegistry);
    // 读取配置文件的核心方法
    beanDefinitionReader.loadBeanDefinitions("配置文件路径");
    return (BeanFactory)registry;
}

②解析配置及后处理 

在上面读取配置文件的步骤中,仅仅是将 <bean> 中的属性值读取出来,这只是一些字符串,最终应用程序却是由各种类型的对象实例构成的,我们需要将这些字符串转换成类信息,这个转化过程就需要定义一个规则,这些规则是由 PropertyEditor 定义,由 CustomEditorConfigurer 帮我们传递给 Spring 容器。经过 PropertyEditor 定义的规则将字符串转换为对应的类型信息之后并存储在 BeanDefinition 中,交给 BeanDefinitionRegistry 管理,容器的启动过程就完成了。其初始化阶段可以用一张图来表示:

判断spring容器是否启动完毕 spring容器启动顺序_spring_02

 

 

2.Bean实例化阶段 

判断spring容器是否启动完毕 spring容器启动顺序_ide_03

① Bean 的实例化

容器在内部实现 Bean 实例化时,采用 策略模式 来决定使用何种方式初始化 bean 实例。InstantiationStrategy 定义了实例化策略的接口,SimpleInstantiationStrategy 继承了它,主要通过 反射 来实现对象的实例化。CglibSubclassingInstantiation 继承了 SimpleInstantiationStrategy 以反射方式实例化的功能,并且还有 CGLIB 动态字节码 生成实例的功能。容器默认采用后者实现。

但是需要注意的是,InstantiationStrategy 实例化对象后并没有直接将对象返回,而是用 BeanWrapper 进行包装,方便后续对此实例进行 属性的设置其设置的依据是通过上面所讲的 PropertyEditor 接口,在第一步构造完成对象之后,Spring 会根据对象实例构造一个BeanWrapperImpl 实例,然后将之前 CustomEditor-Configurer 注册的 PropertyEditor 复制一份给 BeanWrapperImpl 实例这样,当 BeanWrapper 转换类型、设置对象属性值时,就不会无从下手了。

② BeanPostProcessor

当对象实例化完成之后,会将对象实例传到 BeanPostProcessor,这个接口的定义如下:

public interface BeanPostProcessor{
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

 这个接口为我们扩展对象实例的行为提供了极大的便利,其中 postProcessBeforeInitialization 对应的就是上图中 BeanPostProcessor 的前置处理,postProcessAfterInitialization 对应的就是 上图中 BeanPostProcessor 的后置处理。Spring 的 AOP 就是使用 BeanPostProcessor 来为对象生成相应的代理对象。

③ Bean 的初始化

在对象实例话过程调用 BeanPostProcessor 的前置处理 之后,会接着检测对象是否实现了 InitializingBean 接口,如果是,则会调用该接口的 afterPropertiesSet 方法进一步调整对象实例的状态。但是,如果仅仅为了做一个初始化动作而去实现一个接口这样未免有点小题大做,因此 Spring 有提供了另一种方法,就是在 <bean> 中配置 init-method 属性,指定一个方法做对象初始化前的操作。到了这个步骤,对象实例化也快接近尾声了。

④  Bean 的销毁

当所有的一切,该设置的设置,该注入的注入,该调用的调用之后,容器将会检查 singleton 类型的 bean 实例,看起是否实现了 DisposableBean 接口,或者查看对应的 bean 定义是否通过 <bean> 的 destroy-method 属性指定了自定义的对象销毁方法。如果是,就会为该实例注册一个用于对象销毁的回调(Callback),以便在这些 singleton 类型的对象实例销毁之前,执行销毁逻辑。至此,Bean 对象的实例化阶段也完成了。