我们用Spring
就是因为它能帮我们很好的管理Bean
,如果我们能充分的理解Bean
的生命周期,就能在想要的环节去做想做的事情。
周期只有四个!
是的,Spring Bean
的生命周期只有这四个阶段。把这四个阶段和每个阶段对应的扩展点糅合在一起虽然没有问题,但是这样非常凌乱,难以记忆。要彻底搞清楚Spring的生命周期,首先要把这四个阶段牢牢记住。实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段。在这四步之间穿插的各种扩展点,稍后会讲。
- 实例化
Instantiation
- 实例化
- 属性赋值
Populate
- 属性赋值
- 初始化
Initialization
- 初始化
- 销毁
Destruction
- 销毁
实例化 -> 属性赋值 -> 初始化 -> 销毁
主要逻辑都在doCreate()
方法中,逻辑很清晰,就是顺序调用以下三个方法,这三个方法与三个生命周期阶段一一对应,非常重要,在后续扩展接口分析中也会涉及。
createBeanInstance()
-> 实例化
populateBean()
-> 属性赋值
initializeBean()
-> 初始化
源码如下,能证明实例化,属性赋值和初始化这三个生命周期的存在。关于本文的Spring
源码都将忽略无关部分,便于理解:
1 | // 忽略了无关代码 |
至于销毁,是在容器关闭时调用的,详见ConfigurableApplicationContext#close()
常用扩展点
Spring
生命周期相关的常用扩展点非常多,所以问题不是不知道,而是记不住或者记不牢。其实记不住的根本原因还是不够了解,这里通过源码+分类的方式帮大家记忆。
第一大类:影响多个Bean的接口
实现了这些接口的Bean
会切入到多个Bean
的生命周期中。正因为如此,这些接口的功能非常强大,Spring
内部扩展也经常使用这些接口,例如自动注入以及AOP
的实现都和他们有关。
BeanPostProcessor
InstantiationAwareBeanPostProcessor
这两兄弟可能是Spring
扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor
作用于实例化阶段的前后,BeanPostProcessor
作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。通过图能更好理解:
InstantiationAwareBeanPostProcessor
实际上继承了BeanPostProcessor
接口,严格意义上来看他们不是两兄弟,而是两父子。但是从生命周期角度我们重点关注其特有的对实例化阶段的影响,图中省略了从BeanPostProcessor
继承的方法。
1 | InstantiationAwareBeanPostProcessor extends BeanPostProcessor |
InstantiationAwareBeanPostProcessor源码分析:
postProcessBeforeInstantiation
调用点,忽略无关代码:
1 |
|
可以看到,postProcessBeforeInstantiation
在doCreateBean
之前调用,也就是在bean
实例化之前调用的,英文源码注释解释道该方法的返回值会替换原本的Bean
作为代理,这也是Aop
等功能实现的关键点。
postProcessAfterInstantiation
调用点,忽略无关代码:
1 | protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { |
可以看到该方法在属性赋值方法内,但是在真正执行赋值操作之前。其返回值为boolean
,返回false
时可以阻断属性赋值阶段(continueWithPropertyPopulation = false;
)。
关于BeanPostProcessor
执行阶段的源码穿插在下文Aware
接口的调用时机分析中,因为部分Aware功能的就是通过他实现的!只需要先记住BeanPostProcessor
在初始化前后调用就可以了。
第二大类:只调用一次的接口
这一大类接口的特点是功能丰富,常用于用户自定义扩展。
第二大类中又可以分为两类:
Aware
类型的接口- 生命周期接口
无所不知的Aware
Aware
类型的接口的作用就是让我们能够拿到Spring
容器中的一些资源。基本都能够见名知意,Aware
之前的名字就是可以拿到什么资源,例如BeanNameAware
可以拿到BeanName
,以此类推。调用时机需要注意:所有的Aware
方法都是在初始化阶段之前调用的!
Aware
接口众多,这里同样通过分类的方式帮助大家记忆。
Aware
接口具体可以分为两组,至于为什么这么分,详见下面的源码分析。如下排列顺序同样也是Aware
接口的执行顺序,能够见名知意的接口不再解释。
Aware Group1
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
Aware Group2
EnvironmentAware
EmbeddedValueResolverAware
这个知道的人可能不多,实现该接口能够获取Spring EL
解析器,用户的自定义注解需要支持spel
表达式的时候可以使用,非常方便。ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext
对象,因为ApplicationContext
是一个复合接口,如下:
1 | public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, |
这里涉及到另一道面试题,ApplicationContext
和BeanFactory
的区别,可以从ApplicationContext
继承的这几个接口入手,除去BeanFactory
相关的两个接口就是ApplicationContext
独有的功能,这里不详细说明。
Aware调用时机源码分析
详情如下,忽略了部分无关代码。代码位置就是我们上文提到的initializeBean方法详情,这也说明了Aware都是在初始化阶段之前调用的!
1 | // 见名知意,初始化阶段调用的方法 |
可以看到并不是所有的Aware
接口都使用同样的方式调用。Bean××Aware
都是在代码中直接调用的,而ApplicationContext
相关的Aware
都是通过BeanPostProcessor#postProcessBeforeInitialization()
实现的。感兴趣的可以自己看一下ApplicationContextAwareProcessor
这个类的源码,就是判断当前创建的Bean
是否实现了相关的Aware
方法,如果实现了会调用回调方法将资源传递给Bean
。
至于Spring
为什么这么实现,应该没什么特殊的考量。也许和Spring
的版本升级有关。基于对修改关闭,对扩展开放的原则,Spring
对一些新的Aware
采用了扩展的方式添加。
BeanPostProcessor
的调用时机也能在这里体现,包围住invokeInitMethods
方法,也就说明了在初始化阶段的前后执行。
关于Aware
接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了。每组中各个Aware
方法的调用顺序其实没有必要记,有需要的时候点进源码一看便知。
简单的两个生命周期接口
至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是Spring
帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。
InitializingBean
对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd);
方法中调用。
有一点需要注意,因为Aware
方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware
接口获取的资源,这也是我们自定义扩展Spring
的常用方式。
除了实现InitializingBean
接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。DisposableBean
类似于InitializingBean
,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()
方法作为入口,实现是通过循环取所有实现了DisposableBean
接口的Bean
然后调用其destroy()
方法 。感兴趣的可以自行跟一下源码。
扩展阅读: BeanPostProcessor 注册时机与执行顺序
Spring
所做的事情就是把各种方式定义的Java
类变成它的BeanDefinition
,然后通过Bean工厂
变成Bean
放入到它的各种容器中,这样子就被Spring
所管理了。
注册时机
我们知道BeanPostProcessor
也会注册为Bean
,那么Spring
是如何保证BeanPostProcessor
在我们的业务Bean之前初始化完成呢?
请看我们熟悉的refresh()方法的源码,省略部分无关代码:
1 |
|
可以看出,Spring
是先执行registerBeanPostProcessors()
进行BeanPostProcessors
的注册,然后再执行finishBeanFactoryInitialization
初始化我们的单例非懒加载的Bean
。
执行顺序
BeanPostProcessor
有很多个,而且每个BeanPostProcessor
都影响多个Bean
,其执行顺序至关重要,必须能够控制其执行顺序才行。关于执行顺序这里需要引入两个排序相关的接口:PriorityOrdered、Ordered
PriorityOrdered
是一等公民,首先被执行,PriorityOrdered
公民之间通过接口返回值排序Ordered
是二等公民,然后执行,Ordered
公民之间通过接口返回值排序- 都没有实现是三等公民,最后执行
在以下源码中,可以很清晰的看到Spring
注册各种类型BeanPostProcessor
的逻辑,根据实现不同排序接口进行分组。优先级高的先加入,优先级低的后加入。
1 | // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. |
根据排序接口返回值排序,默认升序排序,返回值越低优先级越高。
1 | /** |
PriorityOrdered
、Ordered
接口作为Spring
整个框架通用的排序接口,在Spring
中应用广泛,也是非常重要的接口。
总结
Spring Bean
的生命周期分为四个阶段
和多个扩展点
。扩展点又可以分为影响多个Bean
和影响单个Bean
。整理如下:
四个阶段
- 实例化
Instantiation
- 属性赋值
Populate
- 初始化
Initialization
- 销毁
Destruction
多个扩展点
- 影响多个
Bean
BeanPostProcessor
InstantiationAwareBeanPostProcessor
- 影响单个
Bean
- Aware
- Aware Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- Aware Group2
- EnvironmentAware
- EmbeddedValueResolverAware
- ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
- Aware Group1
- 生命周期
- InitializingBean
- DisposableBean
- Aware
至此,Spring Bean
的生命周期介绍完毕,由于作者水平有限难免有疏漏,欢迎留言纠错。
参考地址
如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。如果想加入微信群的话一起讨论的话,请加管理员简栈文化-小助手(lastpass4u),他会拉你们进群。