從BeanFactory原始碼看Bean的生命週期

2022-11-04 06:00:46

下圖是我搜尋「Spring Bean生命週期」找到的圖片,來自文章——Spring Bean的生命週期

下面,我們從AbstractAutowireCapableBeanFactory的原始碼中來分析這張圖的各個階段到底是怎麼執行的。BeanFactory的基本原始碼解讀在Spring BeanFactory介面分析&原始碼解讀這篇文章中,如果讀本篇文章稍顯吃力,可以先去看看上面那篇。

我們所用到的BeanFactory,ApplicationContext基本都繼承了AbstractAutowireCapableBeanFactory,它是一個具有自動裝載能力的BeanFactory,它可以響應@Autowire註解,所以,單獨分析這個類不是沒用的,而且很有必要。

同時,由於Spring的BeanFactory層次結構中大量的使用了模板模式,所以我們可能在這個類的父子類中跳入跳出。

Bean生命週期簡單描述#

我們先不看那些繁雜的生命週期方法回撥,只看核心的部分,也就是圖中四個大的黃色塊

  1. 根據BeanDefinition建立Bean,這個過程稱為範例化
  2. 填充Bean的屬性
  3. 這時,Bean已經建立完畢並可以投入使用,這時需要呼叫Bean的初始化方法(如果使用者指定了的話),這個過程稱為初始化
  4. Bean被銷燬

所以,可以將Bean的建立歸納為:

  1. 範例化
  2. 設定屬性
  3. 初始化
  4. 銷燬

雖然上面我們把大部分的繁雜的生命週期Hook給遮蔽了,總結出了四個核心的過程,但是這些Hook給了Spring框架帶來了無盡的靈活性,所以也是非常重要的。但它們太容易讓人眼花了,所以在繼續之前,我們有必要先介紹一下那些東西都是什麼,是用來解決什麼問題的。

BeanPostProcessor介面#

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;
	}

}

從方法名上看,xxxxBeforeInitializationxxxAfterInitialization意思是在初始化階段前後做一些事,它的引數中,有實際建立出來的Bean和Bean的名字,該方法預設情況下返回原始的bean,也可以返回該bean的某種代理,實際上AOP就是通過這個介面來實現bean代理的返回的。

所以,BeanPostProcessor實際關心的是Bean的初始化階段

ConfigurableBeanFactory介面的addBeanPostProcessor方法可以向BeanFactory中註冊BeanPostProcessor

InstantiationAwareBeanPostProcessor#

首先,它繼承BeanPostProcessor,所以它是一個BeanPostProcessor。但是從名字來看,InstantiationAware表示它更關心對於Bean的範例化階段的感知,而不是初始化階段,它發生在初始化階段前面

它的方法如下:

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}

	default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}

	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}

    // 省略一個過時方法...
}

首先,xxxBeforeInstantiationxxxAfterInstantiation是很容易和之前的兩個搞混的,不過以Instantiation結尾代表著它們關心的是Bean範例化的前後,在範例化前,該方法同樣允許返回一個代替該Bean的物件,不過這次由於Bean還沒有實際建立出來,所以它的引數中沒有Bean物件,而是該Bean的Class物件。而在範例化後,它允許返回一個布林值來指定是否該對該Bean的屬性進行設定(true設定,false跳過)。

Aware生命週期感知介面#

Aware介面裡啥也沒有,有方法的是它的子介面

public interface Aware { }

Aware被一個想要感知到框架中的某種資訊的Bean實現,比如一個Bean可能對建立它的Bean工廠感興趣,那麼它可以實現這個介面:

public interface BeanFactoryAware extends Aware {

	void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}

Bean工廠會在該Bean的初始化階段檢測該Bean是否實現了這個介面,如果實現了就呼叫它的setBeanFactory方法將工廠設定進去。

請注意,Aware被Bean實現,作用於單個Bean,BeanPostProcessor被註冊到Bean工廠中,作用於工廠中的每個Bean。

範例化Bean&屬性設定#

這圖裡所描述的是,建立Bean時先從BeanDefinition開始,然後範例化Bean,在範例化前後,InstantiationAwareBeanPostProcessor會被呼叫。

下面從doGetBean方法開始(getBean方法實際呼叫的方法,它已經是AbstractBeanFactory中的方法了),看下面的程式碼需要注意,Spring中Bean的作用域可以分為Singleton、Prototype和其它,其中Singleton和Prototype是Spring框架原生支援的,其它作用域需要自行擴充套件,比如SpringWebMVC擴充套件了Session等作用域。所以你看下面的程式碼時也要在腦袋裡把它們分成Singleton、Prototype和其它作用域,要不然你可能就被這很長很長的程式碼搞迷糊了:

protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
        throws BeansException {

    String beanName = transformedBeanName(name);
    Object beanInstance;
    // ...

        try {
            // 根據BeanName獲取BeanDefinition
            // MergedBeanDefinition是將它和它的祖先Bean整合,這裡可以先忽略,就當作普通的BeanDefinition
            RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // 如果是Singleton,按Singleton的方法建立
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        // [+] 實際建立Bean
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {}
                });
                beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
            // 如果是Prototype,按Prototype的方法建立
            else if (mbd.isPrototype()) {
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    // [+] 實際建立Bean
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }
            // 如果是其它作用域,那麼就放到其它作用域中建立
            // 這裡的邏輯和Singleton很像,在Singleton建立中
            // Bean放到SingletonBeanRegistry中管理,而這個
            // 放到對應的作用域中管理
            else {
                String scopeName = mbd.getScope();
                Scope scope = this.scopes.get(scopeName);
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            // [+] 實際建立Bean
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {}
            }
        }
        catch (BeansException ex) {}
    }

    return adaptBeanInstance(name, beanInstance, requiredType);
}

所以,不管是哪個作用域,它們都呼叫了createBean來建立Bean,AbstractBeanFactory中並沒有實現這個方法,createBeanAbstractAutowireCapableBeanFactory抽象類實現的:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    RootBeanDefinition mbdToUse = mbd;

    try {
        // 在Bean範例化之前,讓一些關心範例化階段的BeanPostProcessor得到執行
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        // 如果返回的bean不是null,那麼結束整個階段,直接返回這個值作為bean
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {}

    try {
        // 範例化Bean
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {}

    catch (Throwable ex) {}
}

所以,resolveBeforeInstantiation方法應該就是查詢那些InstantiationAwareBeanPostProcessor,然後呼叫它們。

InstantiationAwareBeanPostProcessor的before hook#

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 應用BeanPostProcessor的beforeInstantiation
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 呼叫BeanPostProcessors的初始化後方法,注意是初始化後不是範例化後
                    // 前提是before方法返回了一個物件
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

我們可以看到,這個方法的程式碼非常簡單,雖然還沒寫明,但是99%就是呼叫所有的InstantiationAwareBeanPostProcessor了,兩個apply應該就是做這個工作的。我們不妨點進去看一個:

@Nullable
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
        Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
        if (result != null) {
            return result;
        }
    }
    return null;
}

這不就是對所有的InstantiationAwareBeanPostProcessor進行遍歷呼叫嗎,取第一個返回結果的Processor的結果。大家說,這裡用到了什麼設計模式?

InstantiationAwareBeanPostProcessor before hook的使用#

下面,我們自己建立一個實現類,它的功能就是列印所有進來的Bean名字和型別:

public class MyInstantiationProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("[+] > MyInstantiationProcessor before bean instantiation : " + beanName + " => " + beanClass.getName());
        return null;
    }
}

下面,我們把它設定到BeanFactory中,然後嘗試獲取Bean:

factory.addBeanPostProcessor(new MyInstantiationProcessor());
Workbench workbench = factory.getBean(Workbench.class);
System.out.println(workbench);

輸出:

[+] > MyInstantiationProcessor before bean instantiation : workbench => top.yudoge.springserials.basic.beanfactory.beans.Workbench
[+] > MyInstantiationProcessor before bean instantiation : person => top.yudoge.springserials.basic.beanfactory.beans.Person
Workbench(operator=Person(name=Yudoge))

因為Workbench物件依賴Person物件,所以引起了兩個物件的連鎖建立,最後一行我們得到了Workbench物件。

下面我們嘗試讓BeanPostProcessor針對Person類返回一個另外的Bean,而不是null

public class MyInstantiationProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("[+] > MyInstantiationProcessor before bean instantiation : " + beanName + " => " + beanClass.getName());

        if (beanClass.getName().equals(Person.class.getName())) {
            return new Person("我是MyInstantiationProcessor返回的Person");
        }
        return null;
    }
}

執行:

[+] > MyInstantiationProcessor before bean instantiation : workbench => top.yudoge.springserials.basic.beanfactory.beans.Workbench
[+] > MyInstantiationProcessor before bean instantiation : person => top.yudoge.springserials.basic.beanfactory.beans.Person
Workbench(operator=Person(name=我是MyInstantiationProcessor返回的Person))

成功的返回了我們建立出來的Person。

對目前的InstantiationAwareBeanPostProcessor的before階段做一個總結:

  1. BeanFactory會在建立Bean之前呼叫所有這種Processor的before方法
  2. 如果在before中返回了一個物件,那麼這個物件就會代替原來的Bean,並且該bean的初始化後(不是範例化後)方法會被立即呼叫
  3. 否則,就是before中返回null,這時進入正常的Bean建立流程

這個總結只是AbstractAutowireCapableBeanFactory中的實現方式,是否有其它BeanFactory以其它方式實現,暫不明確

實際範例化Bean#

所以,當InstantiationAwareBeanPostProcessor沒有返回一個替代物件時,進入正常的Bean建立流程,開始範例化Bean。

回到AbstractAutowireBeanFactorycreateBean方法:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    RootBeanDefinition mbdToUse = mbd;

    try {
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) { }

    try {
        // 建立Bean
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
        throw ex;
    }
    catch (Throwable ex) {}
}

這個doCreateBean方法就是用來實際範例化Bean的:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {

    BeanWrapper instanceWrapper = null;
    // 如果是Singleton,從快取中拿原來的Bean
    if (mbd.isSingleton()) {
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
        // 範例化Bean
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 從BeanWrapper中拿出實際的Bean物件
    Object bean = instanceWrapper.getWrappedInstance();

    // ...
}

向populateBean方法中試探——InstantiationAwareBeanPostProcessor的after方法#

doCreateBean方法裡有這樣兩行:

populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);

很明顯,它們代表了Bean生命週期的屬性設定階段和初始化階段,但是到目前為止,我們還沒有看到InstantiationAwareBeanPostProcessor的除了before以外的另兩個方法被呼叫。雖然populateBean方法名看起來就是設定Bean屬性了,但我們也只能往下看,沒準InstantiationAwareBeanPostProcessor的另外兩個方法在這個populateBean設定屬性之前被呼叫了呢?

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 呼叫所有InstantiationAwareBeanPostProcessor的BeanPostProcessor
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                return;
            }
        }
    }

    // ...
}

我日尼瑪,果然啊!!!進來就開始呼叫InstantiationAwareBeanPostProcessor的after方法

所以,做個小總結:

  1. 對於那些InstantiationAwareBeanPostProcessor沒有攔截(before範例化方法返回null的)的Bean,InstantiationAwareBeanPostProcessor的after範例化方法也會被呼叫
  2. 而對於那些before範例化方法沒有返回null的,這個after範例化方法不會走,直接呼叫了after初始化方法,也就是說把範例化到初始化中間的過程都跳過了

InstantiationAwareBeanPostProcessor的postProcessProperties方法#

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    // 呼叫after範例化方法
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                return;
            }
        }
    }

    // 獲取所有屬性
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    // 自動注入,自動注入是針對pvs的,而不是bean本身
    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }

    // 對於所有的InstantiationAwareBeanPostProcessor,呼叫它們的屬性設定方法
    boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

    PropertyDescriptor[] filteredPds = null;
    if (hasInstAwareBpps) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        // 對於所有InstantiationAwareBeanPostProcessor,呼叫它的postProcessProperties方法
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            // 如果該方法返回的新pvs為null,那麼再呼叫postProcessPropertyValues
            if (pvsToUse == null) {
                // 該方法預設返回初始pvs
                pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                if (pvsToUse == null) {
                    return;
                }
            }
            // 讓pvs等於兩次BeanProcessor方法呼叫後返回的pvs
            pvs = pvsToUse;
        }
    }

    // 實際設定Bean屬性
    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

在這裡,我們可以看到,BeanFactory並沒有實際設定屬性,而是先用一個pvs資料結構來儲存所有待設定的屬性,自動注入時也操作的是pvs。這給了InstantiationAwareBeanPostProcessor可以對屬性值進行二次修改的能力。

InstantiationAwareBeanPostProcessor的兩個與屬性相關的方法都可以返回新的pvs,你可以對原始pvs進行改動。而postProcessProperties方法預設返回null,就是不改動,postProcessPropertyValues方法預設返回原始pvs,也是不改動。

稍後,BeanFactory會把pvs應用到Bean中。

postProcessProperties方法的實戰#

這裡,我們檢測如果pvs中有名為operator的屬性要設定,我們就建立一個新的pvs,並覆蓋它的operator屬性,並返回它,否則我們返回null,也就是不覆蓋屬性:

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
    if (pvs.contains("operator")) {
        MutablePropertyValues clonedPvs = new MutablePropertyValues(pvs);
        clonedPvs.addPropertyValue("operator", new Person("修改了pvs之後的person"));
        return clonedPvs;
    }
    return null;
}

結果,由於autowire階段Person已經被建立了,所以結果中person的範例化階段也被列印了:

[+] > MyInstantiationProcessor before bean instantiation : workbench => top.yudoge.springserials.basic.beanfactory.beans.Workbench
[+] > MyInstantiationProcessor before bean instantiation : person => top.yudoge.springserials.basic.beanfactory.beans.Person
Workbench(operator=Person(name=修改了pvs之後的person))

由於我不瞭解直接修改原始pvs會不會有副作用,所以我選擇了克隆一個物件

這兩個階段最後的總結#

回到這個圖上

  1. 從BeanDefinition建立範例化Bean
  2. 範例化之前如果有InstantiationAwareBeanPostProcessor,呼叫before範例化方法
  3. 如果並沒有一個範例化BeanPostProcessor接管Bean建立,那麼進入正常範例化階段
  4. 範例化Bean
  5. 呼叫InstantiationAwareBeanPostProcessor的after範例化方法
  6. 對pvs進行設定
  7. 呼叫InstantiationAwareBeanPostProcessor的postProcessProperties方法對pvs進行修改
  8. 實際的Bean屬性設定

初始化階段#

看起來挺複雜的,其實很簡單:

主要分為幾個階段:

  1. Aware介面的回撥
  2. BeanPostProcessor的before初始化回撥
  3. 各種初始化方法的回撥
  4. BeanPostProcessor的after初始化回撥

所以,初始化階段其實沒做任何實際的事,只是對各種生命週期方法和Bean感知方法進行回撥,通知它們Bean已經初始化了。或者也可以理解為,初始化階段做的最主要的工作就是呼叫Bean的aware感知方法和初始化方法

// doCreateBean
// 屬性設定階段
populateBean(beanName, mbd, instanceWrapper);
// 初始化階段
exposedObject = initializeBean(beanName, exposedObject, mbd);

進入initalizeBean,可以看到裡面的程式碼正對應著圖中的每一步:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {

    // 呼叫感知方法
    invokeAwareMethods(beanName, bean);

    // 呼叫BeanPostProcessor的before初始化方法
    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    // 呼叫自定義初始化方法
    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }

    // 呼叫BeanPostProcessor的after初始化方法
    catch (Throwable ex) {}
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

Aware感知方法的呼叫#

進入invokeAwareMethod方法,裡面對BeanNameAwareBeanClassLoaderAwareBeanFactoryAware做了檢測,並呼叫了對應的設定方法:

private void invokeAwareMethods(String beanName, Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
            }
        }
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

對於BeanFactory,它只支援這些Aware,ApplicationContext會支援更多的Aware。

Aware感知方法的實戰#

Workbench類實現BeanFactoryAware介面並列印出建立它的BeanFactory:

@Data
public class Workbench implements BeanFactoryAware {
    @Autowired
    private Person operator;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactory => " + beanFactory);
    }
}

需要注意的是,一旦你的Bean實現了某個Aware介面,就證明它要感知到某些框架中的東西,這會讓它直接與框架產生耦合。

BeanPostProcessor before初始化的呼叫#

這裡和之前的套路一樣,並且before方法可以返回一個包裝過的Bean做為代理(預設不包裝,這時wrappedBean==bean)

	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {

        invokeAwareMethods(beanName, bean);

        // 進行before初始化呼叫
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

    // ...
}

遍歷每個BeanPostProcessor,呼叫before初始化方法:

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessBeforeInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

沒啥好解釋的,實際上InstantiationAwareBeanPostProcessor的過程和它差不多,並且比它複雜。

init-method的呼叫#

// 呼叫before初始化
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
    // 呼叫init-method
    invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
    throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
}

那麼我們來檢視invokeInitMethods方法:

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
        throws Throwable {

    // 該Bean是否是initializingBean的範例
    boolean isInitializingBean = (bean instanceof InitializingBean);
    // 如果是,並且有`afterPropertiesSet`方法
    if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
        // 呼叫afterPropertiesSet方法
        ((InitializingBean) bean).afterPropertiesSet();
    }

    if (mbd != null && bean.getClass() != NullBean.class) {
        // 獲取init-method名字
        String initMethodName = mbd.getInitMethodName();
        // 如果`initMethodName`不是空並且`initMethodName`並不和`afterPropertiesSet`同名且不是InitalizingBean(防止重複呼叫),並且Bean中實際有這個方法
        if (StringUtils.hasLength(initMethodName) &&
                !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
            // 呼叫initmethod
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

所以,BeanFactory先是對於實現了InitializingBean的Bean的afterPropertiesSet進行呼叫,然後再對使用者指定的init-method進行呼叫。

InitializingBean實戰#

@Data
public class Workbench implements InitializingBean {
    @Autowired
    private Person operator;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }
}

結果:

afterPropertiesSet
Workbench(operator=Person(name=Yudoge))

init-method實戰#

新增init方法

@Data
public class Workbench implements InitializingBean {
    @Autowired
    private Person operator;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }

    public void init() {
        System.out.println("init");
    }
}

BeanDefinition中設定init方法名

// 設定Init方法名
workbenchRbd.setInitMethodName("init");

結果

afterPropertiesSet
init
Workbench(operator=Person(name=Yudoge))

關於@PostConstruct#

貌似BeanFactory並不支援@PostConstruct,它好像是ApplicationContext通過預註冊InstantiationAwareBeanPostProcessor實現的。這是我猜的。

BeanPostProcessor.post初始化#

略,因為前面已經講了夠多了,猜也能猜到怎麼實現的

初始化階段總結#

  1. 呼叫Aware方法
  2. 呼叫BeanPostProcessor的before初始化
  3. 如果是InitializingBean,呼叫afterPropertiesSet方法
  4. 如果有init-method,呼叫
  5. 呼叫BeanPostProcessor的after初始化

尾聲:Bean的銷燬階段#

回到doCreateBean方法中,最後,該方法判斷了,如果必要的話就將該Bean註冊到DisposableBean中:

try {
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {}

我猜其中的邏輯就是看看該Bean是不是DisposableBean的範例,如果是,註冊到一個什麼表中,方便銷燬Bean時呼叫它的destory方法。

我們先不管,先看BeanFactory中有沒有什麼destroyBean這種方法。果然,在ConfigurableBeanFactory中定義了這個方法,AbstractBeanFactory把它實現了:

@Override
public void destroyBean(String beanName, Object beanInstance) {
    destroyBean(beanName, beanInstance, getMergedLocalBeanDefinition(beanName));
}

protected void destroyBean(String beanName, Object bean, RootBeanDefinition mbd) {
    new DisposableBeanAdapter(
            bean, beanName, mbd, getBeanPostProcessorCache().destructionAware, getAccessControlContext()).destroy();
}

這裡建立了一個什麼DisposableBeanAdapter,然後呼叫了destroy方法,就沒幹別的了。

DisposableBeanAdapter#

DisposableBeanAdapter的描述如下:

/**
 * 實現了`DisposableBean`和`Runnable`的Adapter,對給定的Bean執行多個銷燬步驟:
 * 
 *  - DestructionAwareBeanPostProcessors;
 *  - 本身就實現了DisposableBean的Bean
 *  - BeanDefinition中定義的Bean銷燬方法
 */
class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable 

所以,看起來,整個Bean的銷燬步驟都是這哥們兒一個人完成的嘍。

不過這個圖應該畫錯了,它把DestructionAwareBeanPostProcessors寫成了InstantiationAwareBeanPostProcessor

看看它被呼叫的構造方法裡寫了啥:

public DisposableBeanAdapter(Object bean, String beanName, RootBeanDefinition beanDefinition,
        List<DestructionAwareBeanPostProcessor> postProcessors, @Nullable AccessControlContext acc) {

    this.bean = bean;
    this.beanName = beanName;
    this.nonPublicAccessAllowed = beanDefinition.isNonPublicAccessAllowed();
    // 該Bean是不是可呼叫的DisposableBean
    this.invokeDisposableBean = (bean instanceof DisposableBean &&
            !beanDefinition.hasAnyExternallyManagedDestroyMethod(DESTROY_METHOD_NAME));
    
    // destroy方法名
    String destroyMethodName = inferDestroyMethodIfNecessary(bean, beanDefinition);

    // 和初始化哪裡一樣,防止destroy方法名和DisposableBean的方法名一樣,重複呼叫
    if (destroyMethodName != null &&
            !(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodName)) &&
            !beanDefinition.hasAnyExternallyManagedDestroyMethod(destroyMethodName)) {
        // 如果Bean是一個AutoClosable並且自定義的銷燬方法名也是close的話
        this.invokeAutoCloseable = (bean instanceof AutoCloseable && CLOSE_METHOD_NAME.equals(destroyMethodName));

        if (!this.invokeAutoCloseable) {
            // 如果不是,destroyMethodName就使用使用者指定的並解析對應方法
            this.destroyMethodName = destroyMethodName;
            Method destroyMethod = determineDestroyMethod(destroyMethodName);
            // 省略一些destroy method引數設定相關的程式碼
            this.destroyMethod = destroyMethod;
        }
    }
    // 獲取beanPostProcessors(filterPostProcessors會過濾掉所有非DestructionAwareBeanPostProcessor的類)
    this.beanPostProcessors = filterPostProcessors(postProcessors, bean);
    this.acc = acc;
}

這裡就是做了一些初始化工作,把需要的成員變數都解析出來,方便後面destroy時使用。

然後我們看看destroy方法:

public void destroy() {
    // 呼叫所有DestructionAwareBeanPostProcessor的postProcessBeforeDestruction
    if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
        for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
            processor.postProcessBeforeDestruction(this.bean, this.beanName);
        }
    }

    // 如果是一個disposableBean,呼叫它的destroy
    if (this.invokeDisposableBean) {
        ((DisposableBean) this.bean).destroy();
    }

    // 如果是AutoCloseable(並且自定義銷燬方法名也是close),直接呼叫close
    if (this.invokeAutoCloseable) {
        ((AutoCloseable) this.bean).close();
    }
    // 否則去呼叫自定義方法
    else if (this.destroyMethod != null) {
        invokeCustomDestroyMethod(this.destroyMethod);
    }
    // 有可能存在destroyMethod沒解析,但是destroyMethodName有了的情況,解析並呼叫
    else if (this.destroyMethodName != null) {
        Method destroyMethod = determineDestroyMethod(this.destroyMethodName);
        if (destroyMethod != null) {
            invokeCustomDestroyMethod(ClassUtils.getInterfaceMethodIfPossible(destroyMethod, this.bean.getClass()));
        }
    }
}

實戰DestructionAwareBeanPostProcessor#

建立DestructionAwareBeanPostProcessor

public class MyDestructionProcessor implements DestructionAwareBeanPostProcessor {
    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        System.out.println("[+] DestructionProcessor : " + beanName);
    }
}

向工廠中新增BeanPostProcessor,並銷燬Bean:

factory.addBeanPostProcessor(new MyDestructionProcessor());
factory.destroyBean("workbench", workbench);

結果:

Workbench(operator=Person(name=Yudoge))
[+] DestructionProcessor : top.yudoge.springserials.basic.beanfactory.beans.Workbench

實戰DisposableBean#

讓Bean實現DisposableBean

@Data
public class Workbench implements DisposableBean {
    @Autowired
    private Person operator;

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy");
    }
}

結果:

Workbench(operator=Person(name=Yudoge))
[+] DestructionProcessor : top.yudoge.springserials.basic.beanfactory.beans.Workbench
DisposableBean destroy

實戰CustomDestroyMethod#

新增自定義銷燬方法

@Data
public class Workbench implements DisposableBean {
    @Autowired
    private Person operator;

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy");
    }

    public void customDestroyMethod() {
        System.out.println("Custom destroy method...");
    }
}

在BeanDefinition中定義:

workbenchRbd.setDestroyMethodName("customDestroyMethod");

結果:

Workbench(operator=Person(name=Yudoge))
[+] DestructionProcessor : workbench
DisposableBean destroy
Custom destroy method...

總結#

現在,Bean銷燬階段的邏輯已經全部理解完畢

  1. 呼叫DestructionAwareBeanPostProcessor的before銷燬方法
  2. 如果實現了DisposableBean,呼叫它的Destroy方法
  3. 呼叫自定義destroy-method方法
  4. 說明:真正意義上的銷燬(從容器中移除bean)是在AbstractApplicationContext.close方法中實現的,在此方法中不僅會將bean從容器中移除,還會呼叫到我們實現的這些回撥相關的方法。

最後的總結#

  1. 從BeanDefinition獲取Bean資訊
  2. 呼叫InstantiationAwareBeanPostProcessor的before範例化方法
  3. 如果它返回一個物件,那麼直接進入該物件的初始化後方法
  4. 否則,它返回null,進入正常的Bean生命週期
  5. 範例化Bean
  6. 呼叫populateBean,該方法的目的是對Bean屬性進行設定
  7. 呼叫InstantiationAwareBeanPostProcessor的after範例化方法,該方法的返回值決定是否跳過屬性設定階段
  8. 解析該Bean的pvs,自動注入該pvs
  9. 呼叫InstantiationAwareBeanPostProcessor中兩個和屬性設定有關的方法,允許它們對屬性進行動態修改
  10. 呼叫initializingBean進入初始化階段
  11. 檢測Bean實現了哪些Aware介面,呼叫它們
  12. 呼叫所有BeanPostProcessor的before初始化方法,該方法可以返回Bean的一個代理
  13. 如果Bean是InitializingBean,呼叫它的afterPropertiesSet方法
  14. 如果Bean設定了啟動方法,呼叫啟動方法
  15. 呼叫所有BeanPostProcessor的after初始化方法,該方法可以返回Bean的一個代理
  16. 呼叫destroyBean進入Bean銷燬階段
  17. 建立DisposableBeanAdapter,它負責對Bean的銷燬進行生命週期方法的呼叫
  18. 呼叫所有DestructionAwareBeanPostProcessor的before銷燬方法
  19. 如果是DisposableBean,呼叫destroy方法
  20. 如果設定了destroy-method,呼叫它
參考原文連結:https://www.cnblogs.com/lilpig/p/16477006.html