• spring源码系列5 bean的生命周期


    spring源码系列 bean的生命周期

    本文使用的spring版本是5.3.13

    这一节我从源码的角度来简单分析下spring bean的生命周期,首先有几个前置知识:

    (1) ApplicationContext类型容器的内部持有一个BeanFactory类型的容器,所有的bean实际是存放在这个内置容器中的。

    (2) ApplicationContext类型的容器在启动的过程中会自动创建所有单例类型的bean,容器内部创建bean的时候实际是调用了AbstractBeanFactory#getBean(java.lang.String beanName)这个方法,该方法的内部会先根据bean名称获取bean,如果获取不到就会去创建bean

    结合上边两点可以了解到研究bean的生命周期实际上就是看这个方法的执行逻辑。

    一 、起点: AbstractBeanFactory#getBean(java.lang.String)

    这个方法中只是调用了下自己的另一个方法 doGetBean

    @Override
    	public Object getBean(String name) throws BeansException {
    		return doGetBean(name, null, null, false);
    	}
    

    所以重点在这个doGetBean中

    二、AbstractBeanFactory#doGetBean

    从这个doGetBean方法开始才是真正的获取bean的逻辑,这个方法中先依次从spring的三级缓存中去获取bean,

    如果获取到了就会返回,获取不到才会去走创建逻辑。

    2.1 依次从三级缓存中获取bean

    这里简单贴下获取的代码

    这个getSingleton就是在从三级缓存中获取

    这是获取的详细逻辑,分别从三级缓存中获取,其中

    singletonObjects 一级缓存,就是常说的单例池,用来存储完整的bean

    earlySingletonObjects 二级缓存,用来存储未创建完成的bean

    singletonFactories 三级缓存,里边存的是一个ObjectFactory,执行getObject才会返回一个对象

    这个后边再仔细看,现在只需要对三级缓存有一个了解就行。

    2.2 创建bean

    创建bean在从缓存中没有获取到bean时执行

    就是这个createBean方法,在这里边是创建bean的逻辑。当然这段代码还是在AbstractBeanFactory#doGetBean里边。

    2.3 createBean方法详解

    这个createBean方法在AbstractBeanFactory中是一个抽象方法,在AbstractAutowireCapableBeanFactory中进行了实现。

    AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

    这个方法中主要做了这几件和生命周期有关的事情:

    2.3.1 实例化前

    (1) 执行InstantiationAwareBeanPostProcessor这种后处理器的postProcessBeforeInstantiation方法

    这是一个接口,继承自BeanPostProcessor,是后处理器的一种,在bean实例被创建之前执行,可以在实例化前方法中返回一个对象这样就会提前结束bean的创建,不走后续的逻辑。

    这个resolveBeforeInstantiation的内部就是在执行实例化前,如果返回的bean不是null就会提前结束bean的创建

    上边的applyBeanPostProcessorsBeforeInstantiation就是在执行实例化前方法,大部分情况其内部都返回null,才会执行后续的创建bean逻辑,如果返回的不是null就会提前结束bean的创建,并且这里会提前执行实例化后方法,也是同一个接口中的方法。

    要注意的是spring创建bean的过程中执行的后处理器,也就是BeanPostProcessor,或者其子接口的实现类,是在ApplicationContext类型容器的refresh方法中注册到AbstractBeanFactory的成员变量beanPostProcessors中的,需要执行的时候会从这个成员变量中获取,继续进到applyBeanPostProcessorsBeforeInstantiation方法的内部就可以看到。

    实例化前方法执行完后就开始执行真正的实例化逻辑,doCreateBean方法

    2.3.2 doCreateBean 实例化

    实例化前执行完后执行实例化方法

    继续看看这个doCreateBean内部,这个方法还是在AbstractAutowireCapableBeanFactory#doCreateBean

    这个方法中主要完成了这几个步骤

    2.3.2.1 实例化 创建bean的实例 createBeanInstance

    doCreateBean方法开始有一句createBeanInstance(beanName, mbd, args);,在这个方法的内部通过反射创建出一个对象,完成目标bean的实例化。

    上边只是把对象创建出来了,bean中的各种属性都还没有值,后续的处理中会对bean的属性进行填充。

    2.3.2.2 执行后处理器 MergedBeanDefinitionPostProcessor

    这个接口MergedBeanDefinitionPostProcessor 也是BeanPostProcessor的子接口,在上边创建完对象后就会开始执行这个后处理器的postProcessMergedBeanDefinition方法,可以对bean对象进行后续处理。

    比如有一个实现类AutowiredAnnotationBeanPostProcessor,这个类用来解析类中的Autowired Value,

    就是在这里调用AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition方法来完成对这俩注解的解析,

    然后后续的处理过程中会根据解析结果进行属性注入。

    上边红色框就是在执行后处理的代码,同样的其内部也是从AbstractBeanFactory的成员变量beanPostProcessors中按接口类型去获取对应的实现类然后执行。

    这种后处理器执行完后就要进行bean对象的属性填充。

    2.3.2.3 把半成品bean加入三级缓存

    在这块,spring为了解决bean之间循环依赖的问题,使用三级缓存来解决,在这里会把半成品bean放进三级缓存中。

    上边红色框就是在往三级缓存中放入bean,可以看到三级缓存中放入的是一个lambda表达式,由此可以推测从三级缓存中根据beanName拿到东西后需要调用方法触发lambda才会获取到放入的bean的引用,这块后边讲到三级缓存时再详细看。

    2.3.2.4 属性填充 populateBean

    这个方法AbstractAutowireCapableBeanFactory#populateBean从整体上看是完成对bean属性进行填充的功能,主要有这么几个步骤

    (1) 执行InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation,也就是实例化后方法

    (2)根据bean中属性的名称和类型尝试进行自动注入。当然前提是开启了这个功能,比如在bean标签上使用autowire属性开启

    <bean id="person" class="com.lyy.vo.Person" autowire="byType">
    </bean>
    

    (3) 执行InstantiationAwareBeanPostProcessor#postProcessProperties方法,其中上边提到的Autowired注解修饰的属性就是在这个方法中被注入其他bean对象的,当然实际执行的是实现类AutowiredAnnotationBeanPostProcessor#postProcessProperties方法

    (4) 应用xml文件中使用property标签进行的属性注入

    <bean id="person" class="com.lyy.vo.Person">
            <property name="name" value="lyy"/>
     </bean>
    

    像上边这个配置,perosn中name属性的赋值就是在这块进行的。

    然后属性填充方法就结束了,注意一下spring刚开始设计的时候是基于xml配置的,所以源码中的主线功能都是跟着xml配置走的,对注解的支持实际是通过各种后处理器来实现的。

    2.3.2.5 初始化 initializeBean

    AbstractAutowireCapableBeanFactory#initializeBean方法完成对bean的初始化,在上边属性填充的基础上接着进行处理。

    (1) invokeAwareMethods(beanName, bean);对spring提供的各种aware接口进行处理

    (2) 再次执行一个后处理方法BeanPostProcessor#postProcessBeforeInitialization

    就是俗称的初始化前方法

    (3) 执行 InitializingBean#afterPropertiesSet方法,就是俗称的初始化方法

    (4)再次执行一个后处理器方法 BeanPostProcessor#applyBeanPostProcessorsAfterInitialization

    就是俗称的初始化后

    三、总结

    到这里spring创建bean的过程大部分就执行完了,以上列出了bean生命周期中的一些步骤,看着很多,实际上可以简单总结为 这几类步骤

    (1) 执行后处理的方法 就是BeanPostProcessor还有其各种子接口的实现类中的方法

    (2) 创建bean的实例对象

    (2)bean对象的属性填充

    (4) 处理各种aware接口

    (5) 执行InitializingBean接口的实现类方法

    要注意的是我们平时描述bean的生命周期时看着好像是一个线性的执行过程,但实际各个步骤之间是一个方法调用的嵌套关系,也就是上面哪些步骤是互相嵌套着的,并不是同一个层级的东西,这个需要注意下。

  • 相关阅读:
    用C语言画个简单表格
    魔方阵 奇数偶数都成立
    HDU 1527 取石子游戏
    HDU 2669 Romantic
    21位花朵数(详解)
    博弈论总结(1)
    qsort排序(即快排)
    POJ 1061 青蛙的约会
    HDU 2176 取(m堆)石子游戏
    HDU1061 求n^n的最低位
  • 原文地址:https://www.cnblogs.com/chengxuxiaoyuan/p/16321716.html
Copyright © 2020-2023  润新知