如何記憶 Spring Bean 的生命周期

java清風 發佈 2020-06-16T04:23:52+00:00

」,這是面試官考察 Spring 的常用問題,可見是 Spring 中很重要的知識點。實例化:第 1 步,實例化一個 bean 對象;

1. 引言

「請你描述下 Spring Bean 的生命周期?」,這是面試官考察 Spring 的常用問題,可見是 Spring 中很重要的知識點。

我之前在準備面試時,去網上搜過答案,大多以下圖給出的流程作為答案。

但是當我第一次看到該圖時,就產生了很多困擾,「Aware,BeanPostProcessor......這些都是什麼啊!而且這麼多步驟,太多了,該怎麼記啊!」。

其實要記憶該過程,還是需要我們先去理解,本文將從以下兩方面去幫助理解 Bean 的生命周期:

  1. 生命周期的概要流程:對 Bean 的生命周期進行概括,並且結合代碼來理解;
  2. 擴展點的作用:詳細介紹 Bean 生命周期中所涉及到的擴展點的作用。

2. 生命周期的概要流程

Bean 的生命周期概括起來就是 4 個階段

  1. 實例化(Instantiation);
  2. 屬性賦值(Populate);
  3. 初始化(Initialization);
  4. 銷毀(Destruction)。
  1. 實例化:第 1 步,實例化一個 bean 對象;
  2. 屬性賦值:第 2 步,為 bean 設置相關屬性和依賴;
  3. 初始化:第 3~7 步,步驟較多,其中第 5、6 步為初始化操作,第 3、4 步為在初始化前執行,第 7 步在初始化後執行,該階段結束,才能被用戶使用;
  4. 銷毀:第 8~10步,第8步不是真正意義上的銷毀(還沒使用呢),而是先在使用前註冊了銷毀的相關調用接口,為了後面第9、10步真正銷毀 bean 時再執行相應的方法。

下面我們結合代碼來直觀的看下,在 doCreateBean() 方法中能看到依次執行了這 4 個階段:

// AbstractAutowireCapableBeanFactory.java
protected
 
Object
 doCreateBean
(
final
 
String
 beanName
,
 
final
 
RootBeanDefinition
 mbd
,
 
final
 
@Nullable
 
Object
[]
 args
)
    
throws
 
BeanCreationException
 
{

    
// 1. 實例化
    
BeanWrapper
 instanceWrapper 
=
 
null
;
    
if
 
(
instanceWrapper 
==
 
null
)
 
{
        instanceWrapper 
=
 createBeanInstance
(
beanName
,
 mbd
,
 args
);
    
}

    
Object
 exposedObject 
=
 bean
;
    
try
 
{
        
// 2. 屬性賦值
        populateBean
(
beanName
,
 mbd
,
 instanceWrapper
);
        
// 3. 初始化
        exposedObject 
=
 initializeBean
(
beanName
,
 exposedObject
,
 mbd
);
    
}

    
// 4. 銷毀-註冊回調接口
    
try
 
{
        registerDisposableBeanIfNecessary
(
beanName
,
 bean
,
 mbd
);
    
}

    
return
 exposedObject
;
}

由於初始化包含了第 3~7步,較複雜,所以我們進到 initializeBean() 方法裡具體看下其過程(注釋的序號對應圖中序號):

// AbstractAutowireCapableBeanFactory.javaprotected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {    // 3. 檢查 Aware 相關接口並設置相關依賴    if (System.getSecurityManager() != null) {        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {            invokeAwareMethods(beanName, bean);            return null;        }, getAccessControlContext());    }    else {        invokeAwareMethods(beanName, bean);    }    // 4. BeanPostProcessor 前置處理    Object wrappedBean = bean;    if (mbd == null || !mbd.isSynthetic()) {        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);    }    // 5. 若實現 InitializingBean 接口,調用 afterPropertiesSet() 方法    // 6. 若配置自定義的 init-method方法,則執行    try {        invokeInitMethods(beanName, wrappedBean, mbd);    }    catch (Throwable ex) {        throw new BeanCreationException(            (mbd != null ? mbd.getResourceDescription() : null),            beanName, "Invocation of init method failed", ex);    }    // 7. BeanPostProceesor 後置處理    if (mbd == null || !mbd.isSynthetic()) {        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);    }    return wrappedBean;}

在 invokInitMethods() 方法中會檢查 InitializingBean 接口和 init-method 方法,銷毀的過程也與其類似:

// DisposableBeanAdapter.javapublic void destroy() {    // 9. 若實現 DisposableBean 接口,則執行 destory()方法    if (this.invokeDisposableBean) {        try {            if (System.getSecurityManager() != null) {                AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {                    ((DisposableBean) this.bean).destroy();                    return null;                }, this.acc);            }            else {                ((DisposableBean) this.bean).destroy();            }        }    }    // 10. 若配置自定義的 detory-method 方法,則執行    if (this.destroyMethod != null) {        invokeCustomDestroyMethod(this.destroyMethod);    }    else if (this.destroyMethodName != null) {        Method methodToInvoke = determineDestroyMethod(this.destroyMethodName);        if (methodToInvoke != null) {            invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(methodToInvoke));        }    }}

從 Spring 的源碼我們可以直觀的看到其執行過程,而我們記憶其過程便可以從這 4 個階段出發,實例化、屬性賦值、初始化、銷毀。其中細節較多的便是初始化,涉及了 Aware、BeanPostProcessor、InitializingBean、init-method 的概念。這些都是 Spring 提供的擴展點,其具體作用將在下一節講述。

3. 擴展點的作用

3.1 Aware 接口

若 Spring 檢

關鍵字: