Spring Bean生命周期
生命周期流程
首先看下生命周期图:
再来一张执行过程:
Spring Bean的生命周期只有四个阶段。要彻底搞清楚Spring的生命周期,首先要把这四个阶段牢牢记住。实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段。在这四步之间穿插的各种扩展点。
实例化 Instantiation
属性赋值 Populate
初始化 Initialization
销毁 Destruction
实例化 -> 属性赋值 -> 初始化 -> 销毁
主要逻辑都在doCreateBean()
方法中,逻辑很清晰,就是顺序调用以下三个方法,这三个方法与三个生命周期阶段一一对应,非常重要,在后续扩展接口分析中也会涉及。
createBeanInstance()
-> 实例化populateBean()
-> 属性赋值initializeBean()
-> 初始化
源码如下,能证明实例化,属性赋值和初始化这三个生命周期的存在。关于本文的Spring源码都将忽略无关部分,便于理解:
1 | // 忽略了无关代码 |
至于销毁,是在容器关闭时调用的,详见ConfigurableApplicationContext#close()
在谈生命周期之前有一点需要先明确:
Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
AOP扩展bean生命周期
Spring生命周期相关的常用切入方式非常多,主要有下列方式:
注解方式
在 bean 初始化时会经历几个阶段,首先可以使用注解 @PostConstruct, @PreDestroy 来在 bean 的创建和销毁阶段进行调用。
两个生命周期接口InitializingBean, DisposableBean
还可以实现 InitializingBean
, DisposableBean
这两个接口,也是在初始化以及销毁阶段调用。实例化和属性赋值都是Spring帮助我们做的,能够自己实现的就只有 初始化 和 销毁 两个生命周期阶段.
InitializingBean
对应生命周期的初始化阶段,在源码的invokeInitMethods(beanName, wrappedBean, mbd)
方法中调用。有一点需要注意,因为
Aware
方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。
除了实现InitializingBean
接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。DisposableBean
类似于InitializingBean
,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()
方法作为入口,实现是通过循环取所有实现了DisposableBean
接口的Bean然后调用其`destroy() 方法;
自定义初始化和销毁方法
也可以自定义方法用于在初始化、销毁阶段调用
实现 Aware 接口
Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware
可以拿到BeanName
,以此类推。调用时机需要注意:所有的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
独有的功能.
BeanPostProcessor, InstantiationAwareBeanPostProcessor接口
增强处理器(容器级别),实现 BeanPostProcessor 接口,Spring 中所有 bean 在做初始化时都会调用该接口中的两个方法,, 正因为如此,这些接口的功能非常强大,Spring内部扩展也经常使用这些接口,例如自动注入以及AOP的实现都和他们有关。
这是Spring扩展中最重要的两个接口!
InstantiationAwareBeanPostProcessor
作用于实例化阶段的前后;BeanPostProcessor
作用于初始化阶段的前后;InstantiationAwareBeanPostProcessor
实际上继承了BeanPostProcessor
接口,严格意义上来看他们是两父子;
Aware调用时机源码分析
详情如下,忽略了部分无关代码。代码位置就是initializeBean
方法详情,这也说明了Aware都是在初始化阶段之前调用的!
1 | // 见名知意,初始化阶段调用的方法 |
可以看到并不是所有的Aware接口都使用同样的方式调用。
- Bean××Aware都是在代码中直接调用的;
- ApplicationContext相关的Aware都是通过
BeanPostProcessor#postProcessBeforeInitialization()
实现的。
具体流程可以看一下 ApplicationContextAwareProcessor
这个类的源码,就是判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。
至于Spring为什么这么实现,应该没什么特殊的考量。也许和Spring的版本升级有关。基于对修改关闭,对扩展开放的原则,Spring对一些新的Aware采用了扩展的方式添加。
BeanPostProcessor的调用时机也能在这里体现,包围住 invokeInitMethods
方法,也就说明了在初始化阶段的前后执行。
关于Aware接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了.
实例Demo
User.java
1 | /** |
CustomBeanPostProcessor.java
1 | /** |
BootStrap.java
1 | /** |
运行结果:
1 | 调用InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()函数 |
总结
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)
生命周期
- InitializingBean
- DisposableBean