一文搞懂 Spring Bean 的生命周期
一. 前言
在學習Spring框架的IOC、AOP兩大功能之前,首先需要了解這兩個技術的基礎——Bean。在Spring框架中,Bean無處不在,IOC容器管理的對象就是各種各樣的Bean。理解Bean的生命周期有助于我們更好的理解和使用Spring框架的IOC功能,也有助于我們理解框架如何初始化、使用和管理Bean。接下來我們通過代碼實現觀察 BeanFactory 與 ApplicationContext 中bean的生命周期。
二. BeanFactory中Bean的生命周期
Bean 的生命周期概括起來就是 4 個階段:
- 實例化(Instantiation)
- 屬性賦值(Populate)
- 初始化(Initialization)
- 銷毀(Destruction)
在四個階段中,Spring框架會向外暴露多個擴展點,此時業務代碼可以根據情況,從不同的擴展點切入影響Bean的默認創建行為。

- 其中橙色和綠色的是容器級別生命周期接口,也就是所有的Bean初始化時都會發生作用。主要包含兩個接口InstantiationAwareBeanPostProcessor、BeanPostProcessor,一般被稱為類后處理器。也可根據BeanName進行過濾對指定的Bean進行后處理。
- 藍色的是Bean級生命周期接口方法,只有實現了這些接口的Bean進行初始化時,才會起作用。包含BeanNameAware、BeanFactoryAware、InitializingBean、DisposableBean。
- 灰色的是Bean自身的方法,通過Bean定義構造函數、setter屬性賦值函數、init-method 和 destroy-method 所指定的方法。
三.擴展點
3.1 InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor主要是 Bean 實例化前后的擴展點,通常用于修改特定目標 bean 的默認實例化行為,例如創建具有特殊 TargetSources 的代理(池化目標、延遲初始化目標等),或實現額外的注入策略,如字段注入。
該接口是一個特殊用途的接口,主要供框架內部使用,建議盡可能實現普通的 BeanPostProcessor 接口。
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
/**
* 自身方法,是最先執行的方法,它在目標對象實例化之前調用,該方法的返回值類型是Object,我們可以返回任何類型的值。
* 由于這個時候目標對象還未實例化,所以這個返回值可以用來代替原本該生成的目標對象的實例(比如代理對象)。
* 如果該方法的返回值代替原本該生成的目標對象,后續只有postProcessAfterInitialization方法會調用,
* 其它方法不再調用;否則按照正常的流程走
* @param beanClass
* @param beanName
* @return
* @throws BeansException
*/
@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 在目標對象實例化之后調用,這個時候對象已經被實例化,但是該實例的屬性還未被設置,都是null。
* 因為它的返回值是決定要不要調用postProcessPropertyValues方法的其中一個因素
* (因為還有一個因素是mbd.getDependencyCheck());如果該方法返回false,并且不需要check,
* 那么postProcessPropertyValues就會被忽略不執行;如果返回true,postProcessPropertyValues就會被執行
*/
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
/**
*對屬性值進行修改,如果postProcessAfterInstantiation方法返回false,
*該方法可能不會被調用。可以在該方法內對屬性值進行修改
*/
@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
/**
* 對屬性值進行修改,如果postProcessAfterInstantiation方法返回false,該方法可能不會被調用。可以在該方法內對屬性值進行修改
* 從 5.1 開始,支持 {@link postProcessProperties(PropertyValues, Object, String)}
*/
@Deprecated
@Nullable
default PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
其中postProcessProperties和postProcessPropertyValues作用相似,且觸發時機相同,只是在 5.1 版本之后,更建議使用postProcessProperties。
3.2 Aware
Aware 接口為 Spring 容器的核心接口,是一個具有標識作用的超級接口,實現了該接口的 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回調的方式。
Aware 接口是一個空接口,實際的方法簽名由各個子接口來確定,且該接口通常只會有一個接收單參數的 set 方法,該 set 方法的命名方式為 set + 去掉接口名中的 Aware 后綴,即 XxxAware 接口,則方法定義為 setXxx(),例如 BeanNameAware(setBeanName),ApplicationContextAware(setApplicationContext)。
Aware 的子接口需要提供一個 setXxx 方法,我們知道 set 是設置屬性值的方法,即 Aware 類接口的 setXxx 方法其實就是設置 xxx 屬性值的。例如ApplicationContextAware:
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
詳細介紹參考:IoC 之深入分析 Aware 接口?
3.3 BeanPostProcessor
BeanPostProcessor也稱為Bean后置處理器,它是Spring中定義的接口,在Spring容器的創建過程中(具體為Bean初始化前后)會回調BeanPostProcessor中定義的兩個方法,接口如下:
public interface BeanPostProcessor {
/**
* 初始化前執行的鉤子
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 初始化后,執行的鉤子
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
詳細實現原理參考:IoC 之深入分析 ?BeanPostProcessor
3.4 InitializingBean 和 init-method
InitializingBean 是一個接口,它為 Spring Bean 的初始化提供了一種方式,它有一個 #afterPropertiesSet() 方法,在 bean 的初始化進程中會判斷當前 bean 是否實現了 InitializingBean,如果實現了則調用 #afterPropertiesSet() 方法,進行初始化工作。然后再檢查是否也指定了 init-method ,如果指定了則通過反射機制調用指定的 init-method 方法。代碼如下:
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
詳細介紹參考:IoC 之深入分析 InitializingBean 和 init-method
四. 源碼分析

4.1 bean 實例化
在 #doCreateBean(...) 方法中,首先進行 bean 實例化工作,主要由 #createBeanInstance(...) 方法實現,該方法返回一個 BeanWrapper 對象。BeanWrapper 對象是 Spring 的一個低級 Bean 基礎結構的核心接口,為什么說是低級呢?因為這個時候的 Bean 還不能夠被我們使用,連最基本的屬性都沒有設置。而且在我們實際開發過程中,一般都不會直接使用該類,而是通過 BeanFactory 隱式使用。
BeanWrapper 接口有一個默認實現類 BeanWrapperImpl,其主要作用是對 Bean 進行“包裹”,然后對這個包裹的 bean 進行操作,比如后續注入 bean 屬性。
在實例化 bean 過程中,Spring 采用“策略模式”來決定采用哪種方式來實例化 bean,一般有反射和 CGLIB 動態字節碼兩種方式。
InstantiationStrategy 定義了 Bean 實例化策略的抽象接口,其子類 SimpleInstantiationStrategy 提供了基于反射來實例化對象的功能,但是不支持方法注入方式的對象實例化。CglibSubclassingInstantiationStrategy 繼承 SimpleInstantiationStrategy,他除了擁有父類以反射實例化對象的功能外,還提供了通過 CGLIB 的動態字節碼的功能進而支持方法注入所需的對象實例化需求。默認情況下,Spring 采用 CglibSubclassingInstantiationStrategy。
關于 Bean 實例化的詳細過程,請參考這篇文章:創建Bean的流程
4.2 激活Aware
當 Spring 完成 bean 對象實例化并且設置完相關屬性和依賴后,則會開始 bean 的初始化進程( #initializeBean(...) ),初始化第一個階段是檢查當前 bean 對象是否實現了一系列以 Aware 結尾的的接口。
Aware 接口為 Spring 容器的核心接口,是一個具有標識作用的超級接口,實現了該接口的 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回調的方式。
在初始化階段主要是感知 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 。代碼如下:
// AbstractAutowireCapableBeanFactory.java
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
// BeanNameAware
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
// BeanClassLoaderAware
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
// BeanFactoryAware
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
- BeanNameAware:對該 bean 對象定義的 beanName 設置到當前對象實例中
- BeanClassLoaderAware:將當前 bean 對象相應的 ClassLoader 注入到當前對象實例中
- BeanFactoryAware:BeanFactory 容器會將自身注入到當前對象實例中,這樣當前對象就會擁有一個 BeanFactory 容器的引用。
當然,Spring 不僅僅只是提供了上面三個 Aware 接口,而是一系列:
- LoadTimeWeaverAware:加載Spring Bean時織入第三方模塊,如AspectJ
- BootstrapContextAware:資源適配器BootstrapContext,如JCA,CCI
- ResourceLoaderAware:底層訪問資源的加載器
- PortletConfigAware:PortletConfig
- PortletContextAware:PortletContext
- ServletConfigAware:ServletConfig
- ServletContextAware:ServletContext
- MessageSourceAware:國際化
- ApplicationEventPublisherAware:應用事件
- NotificationPublisherAware:JMX通知
4.3 BeanPostProcessor
初始化第二個階段則是 BeanPostProcessor 增強處理,在該階段 BeanPostProcessor 會處理當前容器內所有符合條件的實例化后的 bean 對象。它主要是對 Spring 容器提供的 bean 實例對象進行有效的擴展,允許 Spring 在初始化 bean 階段對其進行定制化修改,如處理標記接口或者為其提供代理實現。
4.4 InitializingBean 和 init-method
初始化階段,會先執行InitializingBean接口的afterPropertiesSet方法,再執行自定義Init方法
// AbstractAutowireCapableBeanFactory.java
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 首先會檢查是否是 InitializingBean ,如果是的話需要調用 afterPropertiesSet()
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) { // 安全模式
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
// 屬性初始化的處理
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
// 屬性初始化的處理
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
// 判斷是否指定了 init-method(),
// 如果指定了 init-method(),則再調用制定的init-method
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 激活用戶自定義的初始化方法
// 利用反射機制執行
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
4.5 DisposableBean 和 destroy-method
與 InitializingBean 和 init-method 用于對象的自定義初始化工作相似,DisposableBean和 destroy-method 則用于對象的自定義銷毀工作。
當一個 bean 對象經歷了實例化、設置屬性、初始化階段,那么該 bean 對象就可以供容器使用了(調用的過程)。當完成調用后,如果是 singleton 類型的 bean ,則會看當前 bean 是否應實現了 DisposableBean 接口或者配置了 destroy-method 屬性,如果是的話,則會為該實例注冊一個用于對象銷毀的回調方法,便于在這些 singleton 類型的 bean 對象銷毀之前執行銷毀邏輯。
但是,并不是對象完成調用后就會立刻執行銷毀方法,因為這個時候 Spring 容器還處于運行階段,只有當 Spring 容器關閉的時候才會去調用。但是, Spring 容器不會這么聰明會自動去調用這些銷毀方法,而是需要我們主動去告知 Spring 容器。
- 對于 BeanFactory 容器而言,我們需要主動調用
#destroySingletons()方法,通知 BeanFactory 容器去執行相應的銷毀方法。 - 對于 ApplicationContext 容器而言,調用
#registerShutdownHook()方法。
代碼注釋參考:Spring源碼注釋
五. 測試
下面用一個實例來真實看看看上面執行的邏輯,畢竟理論是不能缺少實踐的:
public class LifeCycleBean implements BeanNameAware,BeanFactoryAware,BeanClassLoaderAware,BeanPostProcessor,
InitializingBean,DisposableBean {
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
System.out.println("屬性注入....");
this.test = test;
}
public LifeCycleBean(){ // 構造方法
System.out.println("構造函數調用...");
}
public void display(){
System.out.println("方法調用...");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryAware 被調用...");
}
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware 被調用...");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("BeanClassLoaderAware 被調用...");
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor postProcessBeforeInitialization 被調用...");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor postProcessAfterInitialization 被調用...");
return bean;
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean destroy 被調動...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean afterPropertiesSet 被調動...");
}
public void initMethod(){
System.out.println("init-method 被調用...");
}
public void destroyMethdo(){
System.out.println("destroy-method 被調用...");
}
}
- LifeCycleBean 繼承了
BeanNameAware,BeanFactoryAware,BeanClassLoaderAware,BeanPostProcessor,InitializingBean,DisposableBean六個接口,同時定義了一個test屬性用于驗證屬性注入和提供一個#display()方法用于模擬調用。
配置如下:
<bean id="lifeCycle" class="org.springframework.core.test.lifeCycleBean"
init-method="initMethod" destroy-method="destroyMethdo">
<property name="test" value="test"/>
</bean>
- 配置
init-method和destroy-method。
測試方法如下:
// BeanFactory 容器一定要調用該方法進行 BeanPostProcessor 注冊
factory.addBeanPostProcessor(new LifeCycleBean()); // <1>
LifeCycleBean lifeCycleBean = (LifeCycleBean) factory.getBean("lifeCycle");
lifeCycleBean.display();
System.out.println("方法調用完成,容器開始關閉....");
// 關閉容器
factory.destroySingletons();
運行結果:
構造函數調用...
構造函數調用...
屬性注入....
BeanNameAware 被調用...
BeanClassLoaderAware 被調用...
BeanFactoryAware 被調用...
BeanPostProcessor postProcessBeforeInitialization 被調用...
InitializingBean afterPropertiesSet 被調動...
init-method 被調用...
BeanPostProcessor postProcessAfterInitialization 被調用...
方法調用...
方法調用完成,容器開始關閉....
DisposableBean destroy 被調動...
destroy-method 被調用...
本文參考至:

浙公網安備 33010602011771號