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