浅谈 Spring Bean 的生命周期

一、Bean 的生命周期概述
区别于普通的 Java 对象需要通过 new 创建对象,Spring 的 Bean 由 IoC 容器进行实例化、组装以及管理的。也就是说 Bean 的生命周期完全由 IoC 容器控制。
Spring 容器只能管理 单例(singleton) 作用域的 Bean 的完整生命周期,对于 原型(prototype) 作用域的 Bean,Spring 容器只创建 bean 的实例后便会返回给用户,剩余的生命周期由用户控制。所以 Bean 的生命周期主要指的是 singleton 作用域 的 Bean。
为什么要了解 Bean 的生命周期?
通过了解 Bean 的生命周期可以了解 Bean 是什么时候被创建的,什么时候初始化,什么时候被销毁以及整个 Bean 的生命周期中哪些阶段可以使用哪些增加方法。
这样在实际开发中,可以利用 Bean 的生命周期的指定时刻完成一些自定义的操作。同时面试中 Spring Bean 的生命周期也是常问的一个内容,所以很有必要了解一下。
Bean 的生命周期主要包括四个部分
- 实例化(Instantiation) 
- 属性赋值(Populate) 
- 初始化(Initialization) 
- 销毁(Destruction) 
以 AbstractApplicationContext 的 refresh() 方法为入口,AbstractAutowireCapableBeanFactory 的 doCreateBean 方法完成对 Bean 的实例化、属性注入以及初始化。(具体流程可以看 3.2 的具体流程梳理)
 
 以 AbstractApplicationContext 的 close() 方法为入口,在 DisposableBeanAdapter 的 destory() 方法完成对 Bean 的销毁。(具体流程可以看 3.2 的具体流程梳理)
 
 二、相关接口及方法
Bean 的生命周期中使用到了 Aware 类型的相关接口、InitializingBean/DisposableBean 接口以及一些起到增强作用的接口。了解这些接口可以帮助大家更好地了解 Bean 的生命周期以及更好地拓展定制自己的 Bean 对象。
2.1 各种 Aware 类型的接口
实现 Aware 接口的目的是让程序可以拿到 Spring 容器的当前的运行环境(如当前 Bean 的名称、当前的 BeanFactory、当前的 ApplicationContext 等等资源)。这类接口的调用时机是在 Bean 实例化、属性注入之后,初始化之前。
接下来列出一些常用的子接口,有兴趣的可以从源码中查看还有哪些接口(基本都是见名知意):
BeanNameAware 接口
接口中只有一个方法 void setBeanName(String name) 用于获取当前 Bean 的名称。
 
 BeanFactoryAware 接口
接口中只有一个方法 void setBeanFactory(BeanFactory beanFactory) 用于获取当前的 BeanFactory。
 
 ApplicationContextAware 接口
接口中只有一个方法 void setApplicationContext(ApplicationContext applicationContext) 用于获取当前的 ApplicationContext。
 
 2.2 InitializingBean/DisposableBean 接口
实现 InitializingBean/DisposableBean 接口能够实现自定义初始化方法以及销毁方法。这两个接口的调用时机分别在初始化阶段与销毁阶段。
InitializingBean 接口
接口中只有一个方法 void afterPropertiesSet() 用于自定义初始化行为,在属性注入阶段后执行。
 
 DisposableBean 接口
接口中只有一个方法 void destroy() 用于自定义销毁行为,在销毁阶段执行。
 
 除了接口实现方式外,还有两种可以实现自定义初始化以及销毁的方式:
- 使用 XML 配置文件 或者 Java 配置类 对 Bean 中的 init-method 与 destroy-method 属性进行配置(基于 Bean 自身的初始化和销毁) 
- 使用 注解 @PostConstruct 与 @PreDestroy 修饰方法(作用于 servlet 生命周期的注解) 
2.3 增强方法
BeanFactoryPostProcessor 接口
实现该接口可以增强的方面是:在 BeanFactory 已经初始化而 Bean 实例化之前调用该接口的方法可以修改或添加 Bean 的定义。所以该接口的调用时机是在 Bean 实例化之前。
接口中只有一个方法 void postProcessBeanFactory(ConfigurableListableBeanFactory var1) 用于在 Bean 实例化之前修改 Bean 的定义。
 
 BeanPostProcessor 接口
实现该接口能增强的方面是:在 Bean 实例化后,在初始化阶段的前后自定义行为。可以根据接口方法中的参数来筛选需要自定义行为的 Bean。该接口的调用时机是在 初始化阶段的前后。
该接口有两个方法分别在初始化前和初始化后执行:
- postProcessBeforeInitialization(Object bean, String beanName):初始化前调用 
- postProcessAfterInitialization(Object bean, String beanName):初始化后调用 
 
 InstantiationAwareBeanPostProcessor 接口
实现该接口能增强的方面是:在目标 Bean 实例化的前后可以自定义行为以及在属性注入前可以修改 Bean 的属性设置。
该接口有三个方法(其实还有两个来自于继承 BeanPostProcessor 接口的方法):
- postProcessBeforeInstantiation(Class<?> beanClass, String beanName):在 Bean 实例化之前调用 
- postProcessAfterInstantiation(Object bean, String beanName):在 Bean 实例化之后调用 
- postProcessProperties(PropertyValues pvs, Object bean, String beanName):在 Bean 实例化之后,属性注入之前调用 
 
 三、浅谈生命周期的具体流程
3.1 通过例子展示具体流程
通过一个例子来体现 Bean 的生命周期 的具体流程以及相关接口对应的切入时机
MyBean 类
实现 BeanFactoryPostProcessor 接口
实现 BeanPostProcessor 接口
实现 InstantiationAwareBeanPostProcessor 接口
XML 配置文件
测试类
执行结果
 
 3.2 具体流程梳理
通过上面的例子可以梳理出下面这张 Bean 的生命周期 具体流程图
 
 接下来从源码的角度对流程图的每一个部分进行剖析
从源码看 BeanFactoryPostProcessor # postProcessBeanFactory() 在实例化前执行
 
  
 通过从 refresh() 入口进入按照上面图中的流程可以找到调用 postProcessBeanFactory() 的方法,该方法是在 invokeBeanFactoryPostProcessors(beanFactory) 进入的,而实例化阶段是从 finishBeanFactoryInitialization(beanFactory) 进入的,所以可以说明 BeanFactoryPostProcessor # postProcessBeanFactory() 要先于实例化执行。
 
 从源码看 InstantiationAwareBeanPostProcessor # postProcessBeforeInstantiation() 在实例化前执行
 
  
 通过上面的流程图可以找到调用 postProcessBeforeInstantiation() 的方法是在 resolveBeforeInstantiation(beanName, mbdToUse) 进入的,而实例化阶段是在 doCreateBean(beanName, mbdToUse, args) 进入的,所以可以说明 postProcessBeforeInstantiation() 要先于实例化执行。
 
 从源码看 实例化执行位置 与 属性注入执行位置
 
 实例化阶段发生在 AbstractAutowireCapableBeanFactory 的 createBeanInstance() 方法中。
属性注入阶段发生在 AbstractAutowireCapableBeanFactory 的 populateBean() 方法中。
 
 从源码看 InstantiationAwareBeanPostProcessor # postProcessAfterInstantiation() 与 InstantiationAwareBeanPostProcessor # postProcessPropertyValues() 属性注入阶段前执行
 
 通过上面的流程图可以找到 postProcessAfterInstantiation() 与 postProcessPropertyValues() 在 populateBean() 属性注入方法内被调用。
 
 - postProcessAfterInstantiation() 方法如果找到指定的 bean 就会返回 false,会直接返回不再执行后续方法内容,也就是说后续的属性填充和依赖注入就不会被执行,所以可以看出 postProcessAfterInstantiation() 执行在属性注入阶段前。 
- postProcessPropertyValues() 方法同样发生在 属性填充 之前,如果返回 null 则不会执行后续的属性填充,如果不会为 null,说明有额外添加的属性需要填充,后续方法会执行属性填充。 
从源码看 初始化阶段及其前后发生的调用
 
 根据上面的流程图可以找到初始化阶段进入的入口 initializeBean() 方法,具体代码如下图:
 
 - 先看 Aware 接口的调用 
- 除了上面 BeanXXXAware 接口的调用,如 ApplicationContextAware 接口的调用是发生在 applyBeanPostProcessorsBeforeInitialization 方法中的,也就是是通过 BeanPostProcessor 的 postProcessBeforeInitialization() 实现调用的,具体的可以自己跟一下源码。 
- BeanPostProcessor 的两个实现方法 
- 这两个实现方法分别通过 applyBeanPostProcessorsBeforeInitialization 与 applyBeanPostProcessorsAfterInitialization 方法调用,也可以看出一个在初始化前一个在初始化后执行。 
- invokeInitMethods 初始化方法 
- invokeInitMethods 初始化方法中调用了 InitializingBean 的自定义初始化方法 与 Bean 自身属性中的 init-method 指定的方法。 
从源码看 销毁阶段
 
 根据上面的流程图最终会找到 DisposableBeanAdapter 的 destory() 方法,具体代码如下:
 
 通过 destory() 方法也可以看到销毁阶段先执行 DisposableBean 的销毁方法,再执行 Bean 自身属性 destory-method 指定的方法。











 
    
评论