spring-IOC容器源码分析(一)bean初始化流程
发布日期:2021-08-31 13:48:52 浏览次数:11 分类:技术文章

本文共 4915 字,大约阅读时间需要 16 分钟。

在传统的开发步骤中,如果一个类依赖于另一个类的实例才能完成任务的话,都需要开发者手动new一个实例。之后手动设置到任务类中。但spring的出现,为我们提供了一种称为“依赖注入”(Dependency Inject)的机制。bean的实例化在spring container内部完成,开发者只需要从xml或java code来配置bean达到定制实例化bean。而且,可以让我们通过注解的方式,为我们自动注入需要的依赖。

这样,开发者只需要遵循面向接口来开发应用,把实例化具体类和注入依赖的步骤抽离出业务代码,达到解耦的要求。如果哪天需要使用其他的接口实现依赖,只需要将新的实现配置进spring container。其他业务代码无需更改。这篇文章将围绕着spring是如何实现bean的实例化、如何实现依赖注入来展开,剖析其内部运行机制

测试用例

// 定义一个简单的beanpublic class Car {    public String color;    public String getColor() {        return color;    }    public void setColor(String color) {        this.color = color;    }}// 定义一个配置类,向Spring bean container注册bean@Configurationpublic class Config {    @Bean    public Car car() {        Car car = new Car();        car.setColor("red");        return car;    }}// 编写一个测试类来初始化spring bean container,再从其中获取我们在Config类中定义的bean的实例public class ContextTest {    public static void main(String[] args) {        ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);        Car car = context.getBean(Car.class);        System.out.println(car.getColor());    }}复制代码

运行这个用例,spring bean container将在其内部对我们注入的bean进行实例化、初始化两个步骤。由于这里没有定义bean的作用域,因此我们注册的这个bean(即Car)将以单例的形式存在于container中。每一次调用context.getBean(Car.class)返回的都是同一个Car的实例。

源码分析

说明:以下的流程分析,只围绕spring容器实例化singleton bean(即单例)的主流程进行

主流程

对于spring这样一个比较复杂的框架,其中包含了各种繁杂的业务逻辑。如果一开始就直接深究到每一个细节,我们无法对spring container有一个比较全局的观感,因此在这里先把整个主流程画出来,建立一个全局的蓝图。

解析注册BeanDefinition

注册和解析BeanDefinition,发生在AnnotationConfigApplicationContext#register流程中,其方法内部使用了AnnotatedBeanDefinitionReader#register来实现BeanDefinition的解析和注册;而且在实例化AnnotatedBeanDefinitionReader后,立即向container注册了多个BeanPostProcessor的BeanDefinition(应用于bean的实例化过程)

准备BeanFactory

在AnnotationConfigApplicationContext内部,组合了DefaultListableBeanFactory。在prepareBeanFactory(beanFactory)方法的调用过程中,向beanfactory注入了环境变量、环境属性等。而且注入了多个BeanPostProcessor。

调用BeanFactoryPostProcessor

到了这一步,此时的container已经注册了一系列的BeanFactoryPostProcessor、BeanPostProcessor和应用层相关的bean的BeanDefinition(如当前测试用例的Car)。由于此时所有的bean(包括BeanFactoryPostProcessor、BeanPostProcessor已经应用层的bean)都是以BeanDefinition存在于container中,并未实例化。这就提供了一个机会,添加特定的BeanFactoryPostProcessor,让spring在实例化bean之前,可以定制修改BeanDefinition中的一些数据(如常用的PropertyPlaceholderConfigurer,从外部properties文件读取配置,定义bean的属性);

默认情况下,只调用了ConfigurationClassPostProcessor,作用:

  1. 解析配置类,将其定义的bean注入到beanfactory
  2. 利用ConfigurationClassEnhancer增强了配置类的功能
  3. 注册BeanPostProcessor:ImportAwareBeanPostProcessor
注册BeanPostProcessor

继续上一步流程,处理完BeanDefinition之后,对前面流程中注册到beanfactory中的BeanPostProcessor进行实例化,并添加到beanfactory中的BeanPostProcessor处理队列中。经过这一步之后,beanfactory中的BeanPostProcessor队列存在以下BeanPostProcessor:

  1. ApplicationContextAwareProcessor
  2. ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
  3. PostProcessorRegistrationDelegate$BeanPostProcessorChecker
  4. CommonAnnotationBeanPostProcessor
  5. AutowiredAnnotationBeanPostProcessor
  6. RequiredAnnotationBeanPostProcessor
  7. ApplicationListenerDetector
真正实例化和初始化bean的流程

这个步骤是通过调用DefaultListableBeanFactory#preInstantiateSingletons()方法完成的。实现了预加载所有已注册的bean,这也是ApplicationContext与BeanFactory实现类的区别,在BeanFactory实现类中,只有对一个bean调用getBean(beanname)方法之后才会进行bean的加载。而ApplicationContext则是直接触发其内部的BeanFactory加载所有定义好的bean。

在加载bean的过程中,涉及到三个步骤:

  1. 实例化
  2. 填充属性
  3. 初始化

实例化并初始化bean流程

主流程

实例化

通过调用AbstractAutowireCapableBeanFactory#createBeanInstance来实例化bean(在这之前,spring提供了一个机会可以通过BeanPostProcessor来创建bean,而不是常规的bean实例化,跟AOP相关)。

实例化后,调用了MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition,涉及到的实现类有:

  1. CommonAnnotationBeanPostProcessor,解析类准备@Resource注入需要的InjectionMetadata
  2. AutowiredAnnotationBeanPostProcessor,解析类准备@Autowired注入需要的InjectionMetadata
  3. RequiredAnnotationBeanPostProcessor,空实现
  4. ApplicationListenerDetector,标记了该bean是否为单例
填充bean属性

实例化bean之后,就需要为bean填充bean的属性值了。这一步主要是通过调用:InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation: 可以直接对bean填充属性,之后直接返回。忽略后续的所有填充行为。默认没有进行这一步流程,而是不做任何处理,进入下一个流程

  1. ImportAwareBeanPostProcessor
  2. CommonAnnotationBeanPostProcessor
  3. AutowiredAnnotationBeanPostProcessor
  4. RequiredAnnotationBeanPostProcessor InstantiationAwareBeanPostProcessor#postProcessPropertyValues: 各种自动注入的解析,如@Resource、@Autowired等
  5. ImportAwareBeanPostProcessor
  6. CommonAnnotationBeanPostProcessor
  7. AutowiredAnnotationBeanPostProcessor
  8. RequiredAnnotationBeanPostProcessor 最后通过applyPropertyValues()进行bean的赋值
初始化

进行到这一步时,bean已经从BeanDefinition实例化为了bean的实例,并且填充了属性。是时候进行一下从外部而来的初始化逻辑了(非BeanDefinition相关的)。主要是:

  1. Aware接口的注入
  2. BeanPostProcessor#postProcessBeforeInitialization处理
  3. InitializingBean#afterPropertiesSet实现类的初始化方法
  4. BeanPostProcessor#postProcessAfterInitialization处理
  5. 注册DisposableBean#destroy,在关闭容器时销毁bean的回调操作

总结

以上我们梳理了spring container加载bean的主体流程,spring为我们提供了几大扩展点:

  1. BeanFactoryPostProcessor
  2. BeanPostProcessor
  3. Aware接口实现
  4. InitializingBean#afterPropertiesSet
  5. DisposableBean#destroy 为我们提供了改造bean的契机,方便在实际开发过程中定制化bean的加载。常见的有:
  6. PropertyPlaceholderConfigurer作为BeanFactoryPostProcessor的间接实现类,在bean的加载过程中,读取外部properties文件,对已注册的BeanDefinition进行修改,达到了从外部文件配置bean的目的;
  7. 在数据库连接池的bean定义上,我们都会用@PreDestroy指定一个销毁的回调来释放数据库连接资源

转载地址:https://blog.csdn.net/weixin_34077371/article/details/91361717 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Material Design之-交互效果炸裂的 FloatingActionMenu
下一篇:CSS常用属性和值

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月26日 09时25分38秒