spring源碼:BeanPostProcessor(li)

  在spring管理Bean的初始化過程當中,除了正常管理bean的實例化(初始化、參數注入等)外,還對外提供了豐富的對Bean操做的擴展。例如自定義初始化操做,自定義容器退出時Bean的銷燬操做等等。這段時間看源碼以爲此方面最實際的一個例子就是,咱們在Bean初始化以前以及以後,框架容許咱們作一些統一性的邏輯操做。BeanPostProcessor就完成了這個功能,它可以在裝配Bean的過程當中動態去改變Bean的行爲,達到對Bean的加強。首先須要瞭解整個spring容器對bean初始化的流程,其流程圖以下:spring

上圖中已經完成了容器的初始化(對配置文件的加載和解析),已經進入到實例化階段。可以看出BeanPostProcessor在整個流程中所處的位置,它正好圍繞着bean自定義初始化方法先後。那麼有一個問題,就是既然可以使用afterPropertySet或者init-method來自行初始化咱們的bean,那麼爲何還要這些BeanPostProcessor呢?由於afterPropertySet和init-method更關注自身的業務邏輯處理,而BeanPostProcessor更加通用,好比是否須要感知當前環境的上下文等更具備通用性的邏輯。app

1、使用BeanPostProcessor來完成Bean實例化前、後處理框架

  BeanPostProcessor接口定義了兩個方法,postProcessBeforeInitialization和postProcessAfterInitialization。一看名字便一目瞭然它們各自的做用,那就是在初始化的先後進行預處理和後處理。問題的關鍵在於容器啓動後,BeanFactory是怎麼感知到這些BeanPostProcessor的存在呢?或者說咱們自定義的BeanPostProcessor怎麼可以集成到框架中,讓容器感知和使用咱們自定義的processor?首先,咱們要找到BeanFactory對BeanPostProcessor的處理邏輯代碼,這段代碼在AbstractAutowireCapableBeanFactory類的initializeBean方法中:post

Object wrappedBean = bean; //進入initializeBean方法以前,已經構造了一個Bean對象,不過未經初始化
if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //前處理
}
 
try {
    invokeInitMethods(beanName, wrappedBean, mbd);//這裏有機會調用Bean的afterPropertySet方法以及自定義的初始化方法
}
catch (Throwable ex) {
    throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
                    beanName, "Invocation of init method failed", ex);
}
 
if (mbd == null || !mbd.isSynthetic()) {
    wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);//後處理
}
return wrappedBean;

再進一步看applyBeanPostProcessorsBeforeInitialization方法。this

Object result = existingBean;
// 在這裏容器會遍歷全部已經註冊的BeanPostProcessor,不管是spring框架自身的仍是咱們自定義的。
for (Iterator it = getBeanPostProcessors().iterator(); it.hasNext();) {
    BeanPostProcessor beanProcessor = (BeanPostProcessor) it.next();
    result = beanProcessor.postProcessBeforeInitialization(result, beanName);
}
return result;

能夠看到,咱們徹底有機會在afterPropertySet方法以前就對Bean進行操做,咱們只要在BeanFactory中註冊咱們的BeanPostProcessor(在BeanFactory中註冊咱們的processor),那麼就會在BeanFactory加載Bean的過程當中,回調咱們本身的BeanPostProcessor來完成咱們的動做(上面代碼中循環查找全部註冊的BeanPostProcessor)。不過使用BeanPostProcessor帶來的一個問題就是任何Bean的加載都會調用你註冊過的這個processor,因此一些個性化的業務初始化操做放在這裏是不合適的,業務初始化操做應該放到afterPropertySet(須要實現InitializingBean接口,侵入性較大)或者自定義初始化方法(須要在bean配置文件中指定init-method參數,侵入性較小)中完成。因此,BeanPostProcessor的使用應該是通用的業務邏輯處理。好比咱們常用到的自動綁定(Autowired)就是使用BeanPostProcessor來完成的。咱們來簡單看一下處理autowired的這個processor是如何完成自動綁定成員變量和方法參數的。Autowired的processor類是:spa

AutowiredAnnotationBeanPostProcessor.class

autowired的過程都是在bean實例化以後作的,因此咱們看postProcessAfterInitialization方法的具體實現。調試

// 根據當前bean對象的class信息獲得使用註解autowired的成員變量和方法
InjectionMetadata metadata = findAutowiringMetadata(bean.getClass());
try {
/*
// 實現了將容器中的bean注入到當前對象成員變量的過程。這裏之因此可以拿到容器中的其餘bean,是由於AutowiredAnnotationBeanPostProcessor實現了BeanFactoryAware接口,從而獲得當前容器的BeanFactory。另外具體看進去裏面的實現,autowired的實現實現方式是經過byType實現的。
 
*/
    metadata.injectFields(bean, beanName);
}
catch (Throwable ex) {
    throw new BeanCreationException(beanName, "Autowiring of fields failed", ex);
}
return true;

spring對bean進行初始化的過程默認使用set方法注入。並且屬性注入是在初始化bean以前(參照AbstractAutowireCapableBeanFactory類的doCreateBean方法),也就是說咱們的autowired方式應該是在set方法注入以後,autowired是會覆蓋set方法注入的屬性。咱們能夠作如下實驗來驗證咱們的猜想:咱們在Apple中準備注入另外一個Bean seed,同時使用了set方法和autowired。Apple類中代碼部分以下:code

@Autowired
@Qualifier("seed1")
private Seed seed;
 
public Sort getSeed() {
    return seed;
}
 
public void setSeed(Seed seed) {
    this.seed = seed;
}

配置文件以下:對象

<bean id="apple" class="com.alibaba.china.Apple" >
        <property name="seed">
            <ref bean="seed0" />
        </property>
</bean>
 
<bean id="seed0" class="com.alibaba.china.Seed" >
        <property name="seedName">
            <value>蘋果種子</value>
        </property>
</bean>
    
<bean id="seed1" class="com.alibaba.china.Seed">
        <property name="seedName">
            <value>Apple Seed</value>
        </property>
</bean>

  咱們用set方法注入seed0,用自動綁定的方式注入seed1。因爲BeanPostProcessor在初始化過程當中執行,在set屬性注入以後,因此預期結果seed1被注入。可是運行結果發現是seed0注入了apple對象。blog

  爲何會這樣呢?通過調試發現,在使用set方法屬性注入的過程以前,會處理一類特殊的BeanPostProcessor------InstantiationAwareBeanPostProcessor,它是BeanPostProcessor的擴展接口,可是容器會在set注入以前優先檢查是否存在這類BeanPostProcessor,若是存在InstantiationAwareBeanPostProcessor先執行這類processor。而偏偏巧合的是,AutowiredAnnotationBeanPostProcessor是InstantiationAwareBeanPostProcessor的子類。因此autowired的動做在set方法前作了,set方法的屬性覆蓋了autowired的屬性,因此在上述例子中seed0最終被成功注入到apple這個對象裏面。咱們用類圖能更加形象地描述InstantiationAwareBeanPostProcessor與BeanPostProcessor接口:

當獲取一個bean對象時,主要邏輯在AbstractAutowireCapableBeanFactory類的doCreateBean方法中。其父類中維護一個beanPostProcessors列表,咱們能夠在容器啓動時加入咱們的processor,在執行到doCreateBean中咱們的processor會被回調。咱們根據具體的須要去實現BeanPostProcessor接口或者InstantiationAwareBeanPostProcessor接口。前者主要是初始化先後的處理動做,然後者主要是執行實例化先後的邏輯。

 

ApplicationContext更加簡單地使用BeanPostProcessor:

  若是咱們直接使用BeanFactory,須要把咱們的BeanPostProcessor註冊到BeanFactory上,不然BeanFactory感知不到咱們的processor。而ApplicationContext則在此方面作了加強,咱們只需在配置文件裏面聲明咱們的BeanPostProcessor,ApplicationContext可以自動作到感知。ApplicationContext是如何作到的呢?咱們不妨本身先猜測一下,若是讓咱們本身實現這個加強功能應該怎麼作?大體方向就是本身去掃描配置文件,看全部的bean中有哪些是BeanPostProcessor,而後咱們不分青紅皁白一股腦把全部的BeanPostProcessor都註冊進去。spring對ApplicationContext也正是這麼實現的,具體的描述在另外一片分享中更具體的提到:

2、

相關文章
相關標籤/搜索