Bean的生命周期和Bean后置處理器

簡述

這篇文章參照spring源碼來了解一下bean的創建過程,本文的內容我在學習時畫了一張圖流程圖,結合圖和源碼會比較直觀

BeanFactory

bean工廠,一個創建bean的地方,他的主要方法是getBean,如果已經生產過就直接返回,如果沒有就生產后再返回
其中生產bean走得就是createBean方法,也是本位主要要介紹的方法
同時為了可以支持個性化生產bean的過程,spring使用的bean工廠又支持添加bean后置處理器,并且多種類型,不同類型再bean生產的不同時期調用

private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

用戶通過添加后置處理器可以再某一個特定的生命周期參與bean的創建過程

createBean

這里開始跟蹤createBean源碼,分析重點操作的方法,首先有一句

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

這里先走了resolveBeforeInstantiation,如果有返回直接返回bean,后續所有代碼全部短路,那么就看一下resolveBeforeInstantiation是干嘛

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    // bean定義的beforeInstantiationResolved屬性是true
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // 如果有InstantiationAwareBeanPostProcessor類型的后置處理器
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 執行這些后置處理器(InstantiationAwareBeanPostProcessor)
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    // 如果創建出bean,再執行BeanPostProcessorsAfterInitialization后置處理器
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

總結就是這里開始執行InstantiationAwareBeanPostProcessor類型的后置處理器postProcessBeforeInstantiation方法,給用戶一個機會使用它來完全自定義創建bean,最終如果創建出來了,只執行一個postProcessAfterInitialization類型的后置處理器(這個后置處理器是實例化之后執行的,不管通過哪種方式,最終都會執行)就反回了。
看spring的注釋是這么說的:Typically used to suppress default instantiation for specific target beans(通常用于抑制特定目標 bean 的默認實例化),也就是說用戶如果有些特殊的bean不想按工程創建的套路生產,可以使用這種后置處理器來按自己的套路生產bean(這里我不知道spring有什么場景會使用它,以后再說)

doCreateBean

一般情況下,用戶還是走工廠的套路去創建bean,所以當resolveBeforeInstantiation返回null時,就開始按工廠的套路創建bean了,也就是doCreateBean方法

image.png

下面開始進入doCreateBean方法,還是只關注主干代碼,下面的代碼都是從源碼貼出,只是貼重點

1.createBeanInstance

instanceWrapper = createBeanInstance(beanName, mbd, args);

這一步開始實例化bean,注意實例化和初始化的區別,簡單實例化就是new,初始化就是執行一些初始化方法
這個方法也不用多說了,就是使用反射去創建對象(如果有構造方法注入這里還會更復雜,暫不討論)

2.applyMergedBeanDefinitionPostProcessors

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

執行MergedBeanDefinitionPostProcessor類型的后置處理器,傳出BeanDefinition,beanName,beanType,可以修改BeanDefinition或干點其他事

3.addSingletonFactory

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

添加三級緩存,對bean工廠三級緩存不懂得可以參考手寫Spring之BeanFactory(三級緩存),這里添加的是一個工廠方法,如果方法被執行(出現循環依賴),會執行SmartInstantiationAwareBeanPostProcessor后置處理器(主要是應付代理,后面介紹)

4.populateBean

populateBean(beanName, mbd, instanceWrapper);

給bean填充屬性,這一步有很多重要子步驟

4.1 postProcessAfterInstantiation
for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
            return;
        }
    }
}

這里也是執行InstantiationAwareBeanPostProcessor的后置處理器,但與上面createBean不同的是執行的是postProcessAfterInstantiation方法,剛才那個postProcessBeforeInstantiation返回的是object,如果有返回代表截斷了bean的生產套路自己生產,而這個postProcessAfterInstantiation方法如果返回false也是return,短路了整個populateBean方法,也就是按照自己的套路填充屬性(其實他倆的存在都是因為spring已經很多開放的后置處理器可以調整創建過程,但是不免會有些特殊情況,使用spring處理不來,name就可以使用這種短路的方式完全又用戶自己掌控創建過程,就好像我們做一個文章編寫的系統,給了各種title的輸入框,并且可以選擇,已經很靈活了,但是也不能覆蓋所有用戶需求,那就給你個選擇,你可以按我們的套路編輯文章,也可以選擇使用富文本,愛怎么寫怎么寫)

4.2 pvs
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

這里獲取bean定義中指定的需要填充的屬性,后續還可以加,最終一起填充

4.3 autowireByName | autowireByType
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;
}

獲取bean定義的依賴注入模式,然后調用autowireByNameautowireByType完成依賴注入
這種依賴注入是bean工廠提供的一種實現依賴注入的功能,但我們平時使用的注解形式依賴注入@Autowired并不是使用這個功能,而是使用下面的4.4
這里如果有依賴注入的屬性,并沒有實際調用對象的set去賦值,而是存到pvs,還是最終一起填充

4.4 postProcessProperties
// 再次查找InstantiationAwareBeanPostProcessor類型后置處理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        // 執行postProcessProperties方法
        PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
        // 最終覆蓋pvs(其實是添加)
        pvs = pvsToUse;
    }
}

還是執行InstantiationAwareBeanPostProcessor后置處理器,執行postProcessProperties,用戶可以自定義要填充的屬性,并填充到pvs,@Autowired形式的注入就是寫了一個這個后置處理器來實現的,一會單獨說

4.5 applyPropertyValues
if (pvs != null) {
    applyPropertyValues(beanName, mbd, bw, pvs);
}

如果pvs(要填充的屬性)不為空,執行填充(通過反射去set屬性值)
這里總結一下pvs數據的來源: 1.bean定義里自帶的(4.2) 2.通過bean定義的resolvedAutowireMode去autowire的(4.3) 3.通過后置處理器返回的(4.4)

5.initializeBean

exposedObject = initializeBean(beanName, exposedObject, mbd);

初始化bean,也就是執行初始化方法什么的,進去看看

5.1 invokeAwareMethods
invokeAwareMethods(beanName, bean);

執行aware方法,這個aware翻譯成中文就是感知,其實他的作用也挺簡單,就是有的bean用戶想讓產品用有工廠的聯系方式(beanFactory的引用),bean在工廠中的名字(BeanName),類加載器(BeanClassLoader),只要你的bean繼承了對應的Aware接口,就會給你提供這些信息,比如繼承了BeanFactoryAware,再invokeAwareMethods時就會執行setBeanFactory方法并把BeanFactory傳出來,至于bean愛保存還是拿著干什么隨意。
有三種aware:

  • BeanNameAware 可以獲取到BeanName
  • BeanClassLoaderAware 可以獲取到BeanClassLoader
  • BeanFactoryAware 可以獲取到BeanFactory
5.2 applyBeanPostProcessorsBeforeInitialization
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

執行所有后置處理器的postProcessBeforeInitialization方法,這一步可以獲取到這個階段的bean(wrappedBean里包含,初始化前),并可以返回一個新的bean覆蓋原來的bean,比如創建代理

5.3 invokeInitMethods

執行初始化方法,也就是@PostConstruct注解的方法

5.4 applyBeanPostProcessorsAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

執行所有后置處理器的postProcessBeforeInitialization方法,這一步可以獲取到這個階段的bean(wrappedBean里包含,初始化后),并可以返回一個新的bean覆蓋原來的bean,比如創建代理,spring的AOP實現就是再這里加了后置處理用代理bean覆蓋了原bean

6.getSingleton

Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
        if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
        }

這一步主要看看有沒有提前暴露,如果有則替換當前的bean,主要解決循環依賴和AOP,一會將循環依賴細說

7.registerDisposableBeanIfNecessary

registerDisposableBeanIfNecessary(beanName, bean, mbd);

這步記錄bean,以便銷毀時使用

到此整個創建過程就結束了,這是beanFactory創建bean的整個過程,并預留了很多鉤子(后置處理器)可以實現各種特殊要求,spring的依賴注入和AOP就是通過添加后置處理器來實現的,流程圖

@Autowired(AutowiredAnnotationBeanPostProcessor)

我們平時要實現依賴注入最常用的就是@Autowired,意思要填充屬性
通過對bean創建過程代碼的分析并沒有依靠@Autowired填充屬性的代碼,但是有通過后置處理器填充屬性的邏輯,不錯,@Autowired就是依靠一個特定的后置處理器完成屬性填充的。
這個后置處理器就是AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor繼承了MergedBeanDefinitionPostProcessorInstantiationAwareBeanPostProcessor(其它的先忽略)

image.png

看看分別的實現,做了什么

postProcessMergedBeanDefinition

這個方法是在實例化之后調用


image.png

看看該后置處理器的實現

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}

就不細說了,總結就是掃描bean的@Autowired和@Value注解,并通過beanName緩存起來

postProcessProperties

這個實在填充屬性時調用


image.png
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    metadata.inject(bean, beanName, pvs);
    return pvs;
}

代碼就是獲取上一步的緩存,然后給bean設置屬性(我記得這一步是直接給bean就設置屬性了,pvs并沒有變,但我覺得應該先設置pvs,最后統一在applyPropertyValues的時候實際填充屬性,這個可以自己看代碼去確定)
總之,通過這兩步,1.掃描@Autowired存緩存 2.根據緩存依賴注入 就完成了@Autowired的功能

@AOP(AbstractAutoProxyCreator)

AOP功能實現的方式同樣也是使用后置處理器,即AbstractAutoProxyCreator,是一個抽象類,但主要的方法都在這里,所以就介紹他
主要實現了SmartInstantiationAwareBeanPostProcessorBeanPostProcessor(其它先忽略)

image.png

看看分別的實現,做了什么

getEarlyBeanReference

這一步調用是出現循環依賴時調用


image.png

看看實現

@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
    // 根據beanName和class生成一個key
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    // 使用key存儲bean
    this.earlyProxyReferences.put(cacheKey, bean);
    // wrapIfNecessary
    return wrapIfNecessary(bean, beanName, cacheKey);
}

主要是按特定的key存了一個緩存,然后執行wrapIfNecessary(其實就是如果設置了代理則創建代理)
如果這一步創建了代理,容器中就已經存放了當前bean的代理,所以bean的創建過程最后如果getSingleton獲取到了bean代表提前暴露了,創建了代理所以最終需要返回這個代理的bean對象,也就是

exposedObject = earlySingletonReference;

postProcessAfterInitialization

初始化結束之后執行


image.png

實現

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

這里的邏輯是之前走沒走getEarlyBeanReference(即有沒有提前暴露),如果沒走,執行wrapIfNecessary,這里不懂的可以看看手寫Spring之BeanFactory(三級緩存)這篇文章

wrapIfNecessary

兩個方法都有用到wrapIfNecessary,里面的代碼就不貼了,最重要的是一句

Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

即是創建代理,里面的內容就是創建代理的過程,可以參照我之前的Spring AOP系列文章

最后

spring支持注解依賴注入和AOP,但beanFactory本身不能實現這些功能,而是通過后置處理器方式實現的,那是誰把這些后置處理器交給BeanFactory的吶?答案就是ApplicationContext
over~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容