日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

BeanPostProcessor —— 连接Spring IOC和AOP的桥梁

發(fā)布時(shí)間:2025/7/14 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BeanPostProcessor —— 连接Spring IOC和AOP的桥梁 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前都是從大Boss的視角,來介紹Spring,比如IOC、AOP。

今天換個(gè)視角,從一個(gè)小嘍啰出發(fā),來加深對(duì)Spring的理解。

這個(gè)小嘍啰就是,?BeanPostProcessor?(下面簡稱?BBP?)。

講解思路:

  • BBP怎么用 —— 先學(xué)會(huì)怎么用,再去看原理
  • BBP的觸發(fā)時(shí)機(jī) —— 在整個(gè)Spring Bean初始化流程中的位置
  • BBP自己又是什么時(shí)候被創(chuàng)建的?
  • BBP是如何連接IOC和AOP的?

怎么用

BeanPostProcessor,直譯過來,就是“對(duì)象后處理器”,?那么這個(gè)“后”,是指什么之后呢?

試試便知。

我們先寫一個(gè)對(duì)象,Bean4BBP(?本文的所有代碼,可到?Github?上下載?):

@Component public class Bean4BBP {private static final Logger log = LoggerFactory.getLogger(Bean4BBP.class);public Bean4BBP(){log.info("construct Bean4BBP");} }

?

然后再寫一個(gè)BeanPostProcessor,這時(shí)發(fā)現(xiàn)它是一個(gè)接口,沒關(guān)系,那就寫一個(gè)類實(shí)現(xiàn)它,CustomBeanPostProcessor:

@Component public class CustomBeanPostProcessor implements BeanPostProcessor {private static final Logger log = LoggerFactory.getLogger(CustomBeanPostProcessor.class);public CustomBeanPostProcessor() {log.info("construct CustomBeanPostProcessor");}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Bean4BBP) {log.info("process bean before initialization");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof Bean4BBP) {log.info("process bean after initialization");}return bean;} }

?

然后啟動(dòng)我們的Spring Boot項(xiàng)目(直接運(yùn)行Application類),看這幾條日志打印的順序:

construct CustomBeanPostProcessor construct Bean4BBP process bean before initialization process bean after initialization

?

BBP對(duì)象首先被創(chuàng)建,然后創(chuàng)建Bean4BBP對(duì)象,接著再先后執(zhí)行BBP對(duì)象的postProcessBeforeInitialization和postProcessAfterInitialization方法。

結(jié)論:“對(duì)象后處理器”,指的是“?對(duì)象創(chuàng)建后處理器?”。

我們可以利用它,在對(duì)象創(chuàng)建之后,對(duì)對(duì)象進(jìn)行修改(有什么場合需要用到?思考題,文末回答。)

那么,為什么要分postProcessBeforeInitialization和postProcessAfterInitialization呢?這里的Initialization是什么意思?

觸發(fā)時(shí)機(jī)

我們只需要在CustomBeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法里,打上兩個(gè)斷點(diǎn),一切自然明了。

斷點(diǎn)進(jìn)來,跟著調(diào)用棧這點(diǎn)蛛絲馬跡往回走,真相大白:?

在initializeBean方法里面,先后調(diào)用了applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法,這兩個(gè)方法內(nèi)部,則分別去遍歷系統(tǒng)里所有的BBP,然后逐個(gè)執(zhí)行這些BBP對(duì)象的postProcessBeforeInitialization和postProcessAfterInitialization方法,去處理對(duì)象,以applyBeanPostProcessorsBeforeInitialization為例:

那么夾在applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法中間的invokeInitMethods方法是做什么的呢?

其實(shí)這個(gè)方法就是Spring提供的,用于對(duì)象創(chuàng)建完之后,針對(duì)對(duì)象的一些初始化操作。這就好比你創(chuàng)建了一個(gè)英雄之后,你需要給他進(jìn)行一些能力屬性的初始化、服裝初始化一樣。

要驗(yàn)證這一點(diǎn),很簡單,只需讓Bean4BBP實(shí)現(xiàn)InitializingBean接口:

@Component public class Bean4BBP implements InitializingBean {private static final Logger log = LoggerFactory.getLogger(Bean4BBP.class);public Bean4BBP(){log.info("construct Bean4BBP");}@Overridepublic void afterPropertiesSet() throws Exception {log.info("init Bean4BBP");} }

?

然后重新啟動(dòng)工程,打印順序如下:

construct CustomBeanPostProcessor construct Bean4BBP process bean before initialization init Bean4BBP process bean after initialization

?

BBP是什么時(shí)候被初始化的

從上面的代碼片段,我們已經(jīng)知道,在對(duì)象創(chuàng)建之后,需要遍歷BBP列表,對(duì)對(duì)象進(jìn)行處理。

這也就意味著,?BBP對(duì)象,必須在普通對(duì)象創(chuàng)建之前被創(chuàng)建?。

那么BBP都是在什么時(shí)候被創(chuàng)建的呢?

要回答這個(gè)問題,非常簡單,?我們只需要在CustomBeanPostProcessor的構(gòu)造函數(shù)里打個(gè)斷點(diǎn)?(這下看到先學(xué)會(huì)用,再了解原理的好處了吧)

斷點(diǎn)進(jìn)來,繼續(xù)利用調(diào)用棧,我們找尋到了AbstractApplicationContext的refresh()方法,這個(gè)方法里面調(diào)用了registerBeanPostProcessors方法,里頭就已經(jīng)把BBP列表創(chuàng)建好了,而普通對(duì)象的創(chuàng)建,是在之后的finishBeanFactoryInitialization方法里執(zhí)行的:

網(wǎng)上有個(gè)圖畫的特別好,很好的展示了BBP在Spring對(duì)象初始化流程的位置:


(看到BBP在哪了嗎?)

BBP的典型使用 - AOP

不知道大家在使用Spring AOP時(shí),有沒有發(fā)現(xiàn),帶有切面邏輯的對(duì)象,注入進(jìn)來之后,都不是原來的對(duì)象了,比如下圖:

調(diào)試信息顯示,aspectService是一個(gè)…$$EnhanceBySpringCGlib的對(duì)象,這其實(shí)和Spring AOP用到的動(dòng)態(tài)代理有關(guān)。

關(guān)于Spring AOP的原理,可以參考我之前的回答:?什么是面向切面編程AOP? - Javdroider Hong的回答 - 知乎

這也就意味著,?最終放進(jìn)Spring容器的,必須是代理對(duì)象,而不是原先的對(duì)象?,這樣別的對(duì)象在注入時(shí),才能獲得帶有切面邏輯的代理對(duì)象。

那么Spring是怎么做到這一點(diǎn)的呢?正是利用了這篇文章講到的BBP。

顯然,我只需要寫一個(gè)BBP,在postProcessBeforeInitialization或者postProcessAfterInitialization方法中,對(duì)對(duì)象進(jìn)行判斷,看他需不需要織入切面邏輯,如果需要,那我就根據(jù)這個(gè)對(duì)象,生成一個(gè)代理對(duì)象,然后返回這個(gè)代理對(duì)象,那么最終注入容器的,自然就是代理對(duì)象了。

這個(gè)服務(wù)于Spring AOP的BBP,叫做?AnnotationAwareAspectJAutoProxyCreator?.

利用idea的diagram功能,可以看出它和BBP的關(guān)系:

具體的創(chuàng)建代理對(duì)象并返回的邏輯,在postProcessAfterInitialization方法中,大家自行欣賞。

可以說,如果沒有BBP,那么Spring AOP就只能叫AOP。

BBP是連接IOC和AOP的橋梁。

總結(jié)

這篇文章,主要通過對(duì)BBP的講解,串聯(lián)起之前講到的關(guān)于Spring的知識(shí),希望能夠加深大家對(duì)Spring的理解。

最后,回到開頭提出的四個(gè)問題:

  • BBP怎么用 —— 先學(xué)會(huì)怎么用,再去看原理
  • BBP的觸發(fā)時(shí)機(jī) —— 在整個(gè)Spring Bean初始化流程中的位置
  • BBP自己又是什么時(shí)候被創(chuàng)建的?
  • BBP是如何連接IOC和AOP的?

轉(zhuǎn)載于:https://www.cnblogs.com/yuxiang1/p/9199730.html

總結(jié)

以上是生活随笔為你收集整理的BeanPostProcessor —— 连接Spring IOC和AOP的桥梁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。