[Spring] BeanPostProcessor

1.spring容器擴展點

自定義的實例化管行、初始化厨埋、依賴裝配、依賴檢查等流程捐顷,既可以覆蓋默認的實例化荡陷,也可以增強初始化雨效、依賴注入、依賴檢查等流程

大體意思是可以檢查相應的標識接口完成一些自定義功能實現(xiàn)废赞,如包裝目標對象到代理對象徽龟。

1.第一個BeanPostProcessor擴展點 InstantiationAwareBeanPostProcessor
必須為InstantiationAwareBeanPostProcessor的實現(xiàn)類。
作用是在 createBean 和 doCreateBean之間唉地,進行判斷据悔。

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isDebugEnabled()) {
            logger.debug("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }

作用:

通過如上代碼可以進行實例化的預處理(自定義實例化bean,如創(chuàng)建相應的代理對象)和后處理(如進行自定義實例化的bean的依賴裝配)耘沼。

第二個 BeanPostProcessor 擴展點 SmartInstantiationAwareBeanPostProcessor

doCreateBean里面

if (instanceWrapper == null) {
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}

回調(diào)方法解析構造器,

通過SmartInstantiationAwareBeanPostProcessordetermineCandidateConstructors回調(diào)方法解析構造器极颓,第二個BeanPostProcessor擴展點,返回第一個解析成功(返回值不為null)的構造器組群嗤,如AutowiredAnnotationBeanPostProcessor實現(xiàn)將自動掃描通過@Autowired/@Value注解的構造器從而可以完成構造器注入

第三個BeanPostProcessor擴展點 MergedBeanDefinitionPostProcessor

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName)

執(zhí)行bean定義的合并

第四個BeanPostProcessor擴展點 SmartInstantiationAwareBeanPostProcessor

SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference菠隆;第四個BeanPostProcessor擴展點,當存在循環(huán)依賴時骚烧,通過該回調(diào)方法獲取及早暴露的Bean實例浸赫;

第五個BeanPostProcessor擴展點 populateBean(beanName, mbd, instanceWrapper)

填充屬性

(9.1闰围、InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation赃绊;第五個BeanPostProcessor擴展點,在實例化Bean之后羡榴,所有其他裝配邏輯之前執(zhí)行碧查,如果false將阻止其他的InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation的執(zhí)行和從(9.2到(9.5的執(zhí)行,通常返回true校仑;

(9.2忠售、autowireByName、autowireByType:根據(jù)名字和類型進行自動裝配迄沫,自動裝配的知識請參考【第三章】 DI 之 3.3 更多DI的知識 ——跟我學spring3 3.3.3 自動裝配稻扬;

(9.3、InstantiationAwareBeanPostProcessor的postProcessPropertyValues:第六個BeanPostProcessor擴展點羊瘩,完成其他定制的一些依賴注入泰佳,如AutowiredAnnotationBeanPostProcessor執(zhí)行@Autowired注解注入,CommonAnnotationBeanPostProcessor執(zhí)行@Resource等注解的注入尘吗,PersistenceAnnotationBeanPostProcessor執(zhí)行@ PersistenceContext等JPA注解的注入逝她,RequiredAnnotationBeanPostProcessor執(zhí)行@ Required注解的檢查等等,請參考【第十二章】零配置 之 12.2 注解實現(xiàn)Bean依賴注入 ——跟我學spring3睬捶;

(9.4黔宛、checkDependencies:依賴檢查,請參考【第三章】 DI 之 3.3 更多DI的知識 ——跟我學spring3 3.3.4 依賴檢查擒贸;

(9.5臀晃、applyPropertyValues:應用明確的setter屬性注入觉渴,請參考【第三章】 DI 之 3.1 DI的配置使用 ——跟我學spring3

**(10****徽惋、exposedObject = initializeBean(beanName, exposedObject, mbd); **執(zhí)行初始化Bean流程疆拘;

(10.1、invokeAwareMethods(BeanNameAware寂曹、BeanClassLoaderAware哎迄、BeanFactoryAware):調(diào)用一些Aware標識接口注入如BeanName、BeanFactory隆圆;

(10.2漱挚、BeanPostProcessor的postProcessBeforeInitialization:第七個擴展點,在調(diào)用初始化之前完成一些定制的初始化任務渺氧,如BeanValidationPostProcessor完成JSR-303 @Valid注解Bean驗證旨涝,InitDestroyAnnotationBeanPostProcessor完成@PostConstruct注解的初始化方法調(diào)用,ApplicationContextAwareProcessor完成一些Aware接口的注入(如EnvironmentAware侣背、ResourceLoaderAware白华、ApplicationContextAware),其返回值將替代原始的Bean對象贩耐;

(10.3弧腥、invokeInitMethods : 調(diào)用初始化方法;

(10.3.1潮太、InitializingBean的afterPropertiesSet :調(diào)用InitializingBean的afterPropertiesSet回調(diào)方法管搪;

(10.3.2、通過xml指定的自定義init-method :調(diào)用通過xml配置的自定義init-method

(10.3.3铡买、BeanPostProcessor的postProcessAfterInitialization :第八個擴展點更鲁,AspectJAwareAdvisorAutoProxyCreator(完成xml風格的AOP配置(<aop:config>)的目標對象包裝到AOP代理對象)、AnnotationAwareAspectJAutoProxyCreator(完成@Aspectj注解風格(<aop:aspectj-autoproxy> @Aspect)的AOP配置的目標對象包裝到AOP代理對象)奇钞,其返回值將替代原始的Bean對象澡为;

(11、if (earlySingletonExposure) {

                 Object earlySingletonReference = getSingleton(beanName, false);

        ……

  } :如果是earlySingleExposure景埃,調(diào)用getSingle方法獲取Bean實例媒至;

earlySingleExposure =(mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName))

只要單例Bean且允許循環(huán)引用(默認true)且當前單例Bean正在創(chuàng)建中

(11.1、如果是earlySingletonExposure調(diào)用getSingleton將觸發(fā)【8】處ObjectFactory.getObject()的調(diào)用纠亚,通過【8.1】處的getEarlyBeanReference獲取相關Bean(如包裝目標對象的代理Bean)塘慕;(在循環(huán)引用Bean時可能引起Spring事務處理時自我調(diào)用的解決方案及一些實現(xiàn)方式的風險);

(12****蒂胞、registerDisposableBeanIfNecessary(beanName, bean, mbd) ****: 注冊Bean的銷毀方法(只有非原型Bean可注冊)图呢;

(12.1、單例Bean的銷毀流程

(12.1.1、DestructionAwareBeanPostProcessor的postProcessBeforeDestruction : 第九個擴展點蛤织,如InitDestroyAnnotationBeanPostProcessor完成@PreDestroy注解的銷毀方法注冊和調(diào)用赴叹;

(12.1.2、DisposableBean的destroy:注冊/調(diào)用DisposableBean的destroy銷毀方法指蚜;

(12.1.3乞巧、通過xml指定的自定義destroy-method : 注冊/調(diào)用通過XML指定的destroy-method銷毀方法;

(12.1.2摊鸡、Scope的registerDestructionCallback:注冊自定義的Scope的銷毀回調(diào)方法绽媒,如RequestScope、SessionScope等免猾;其流程和【12.1 單例Bean的銷毀流程一樣】是辕,關于自定義Scope請參考【第三章】 DI 之 3.4 Bean的作用域 ——跟我學spring3

(13****、到此Bean****實例化猎提、依賴注入获三、初始化完畢可以返回創(chuàng)建好的bean****了。

從上面的流程我們可以看到BeanPostProcessor一個使用了九個擴展點锨苏,其實還一個擴展點(SmartInstantiationAwareBeanPostProcessor的predictBeanType在下一篇介紹)疙教,接下來我們看看BeanPostProcessor這些擴展點都主要完成什么功能及常見的BeanPostProcessor。

我將在下一帖子中使用例子來解析這八個擴展點的主要功能伞租,及一些Spring默認提供的BeanPostProcessor主要作用贞谓。

歡迎大家一起探討學習。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肯夏,一起剝皮案震驚了整個濱河市经宏,隨后出現(xiàn)的幾起案子犀暑,更是在濱河造成了極大的恐慌驯击,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耐亏,死亡現(xiàn)場離奇詭異徊都,居然都是意外死亡,警方通過查閱死者的電腦和手機广辰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門暇矫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人择吊,你說我怎么就攤上這事李根。” “怎么了几睛?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵房轿,是天一觀的道長。 經(jīng)常有香客問我,道長囱持,這世上最難降的妖魔是什么夯接? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮纷妆,結果婚禮上盔几,老公的妹妹穿的比我還像新娘。我一直安慰自己掩幢,他們只是感情好逊拍,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著际邻,像睡著了一般顺献。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枯怖,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天注整,我揣著相機與錄音,去河邊找鬼度硝。 笑死肿轨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的蕊程。 我是一名探鬼主播椒袍,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼藻茂!你這毒婦竟也來了驹暑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤辨赐,失蹤者是張志新(化名)和其女友劉穎优俘,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掀序,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡帆焕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了不恭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叶雹。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖换吧,靈堂內(nèi)的尸體忽然破棺而出折晦,到底是詐尸還是另有隱情,我是刑警寧澤沾瓦,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布满着,位于F島的核電站打颤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏漓滔。R本人自食惡果不足惜编饺,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望响驴。 院中可真熱鬧透且,春花似錦、人聲如沸豁鲤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽琳骡。三九已至锅论,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間楣号,已是汗流浹背最易。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炫狱,地道東北人藻懒。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像视译,于是被迫代替她去往敵國和親嬉荆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容