javascript
BeanPostProcessor —— 连接Spring IOC和AOP的桥梁
之前都是從大Boss的視角,來介紹Spring,比如IOC、AOP。
今天換個視角,從一個小嘍啰出發,來加深對Spring的理解。
這個小嘍啰就是,?BeanPostProcessor?(下面簡稱?BBP?)。
講解思路:
- BBP怎么用 —— 先學會怎么用,再去看原理
- BBP的觸發時機 —— 在整個Spring Bean初始化流程中的位置
- BBP自己又是什么時候被創建的?
- BBP是如何連接IOC和AOP的?
怎么用
BeanPostProcessor,直譯過來,就是“對象后處理器”,?那么這個“后”,是指什么之后呢?
試試便知。
我們先寫一個對象,Bean4BBP(?本文的所有代碼,可到?Github?上下載?):
@Component public class Bean4BBP {private static final Logger log = LoggerFactory.getLogger(Bean4BBP.class);public Bean4BBP(){log.info("construct Bean4BBP");} }?
然后再寫一個BeanPostProcessor,這時發現它是一個接口,沒關系,那就寫一個類實現它,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;} }?
然后啟動我們的Spring Boot項目(直接運行Application類),看這幾條日志打印的順序:
construct CustomBeanPostProcessor construct Bean4BBP process bean before initialization process bean after initialization?
BBP對象首先被創建,然后創建Bean4BBP對象,接著再先后執行BBP對象的postProcessBeforeInitialization和postProcessAfterInitialization方法。
結論:“對象后處理器”,指的是“?對象創建后處理器?”。
我們可以利用它,在對象創建之后,對對象進行修改(有什么場合需要用到?思考題,文末回答。)
那么,為什么要分postProcessBeforeInitialization和postProcessAfterInitialization呢?這里的Initialization是什么意思?
觸發時機
我們只需要在CustomBeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法里,打上兩個斷點,一切自然明了。
斷點進來,跟著調用棧這點蛛絲馬跡往回走,真相大白:?
在initializeBean方法里面,先后調用了applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法,這兩個方法內部,則分別去遍歷系統里所有的BBP,然后逐個執行這些BBP對象的postProcessBeforeInitialization和postProcessAfterInitialization方法,去處理對象,以applyBeanPostProcessorsBeforeInitialization為例:
那么夾在applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization方法中間的invokeInitMethods方法是做什么的呢?
其實這個方法就是Spring提供的,用于對象創建完之后,針對對象的一些初始化操作。這就好比你創建了一個英雄之后,你需要給他進行一些能力屬性的初始化、服裝初始化一樣。
要驗證這一點,很簡單,只需讓Bean4BBP實現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");} }?
然后重新啟動工程,打印順序如下:
construct CustomBeanPostProcessor construct Bean4BBP process bean before initialization init Bean4BBP process bean after initialization?
BBP是什么時候被初始化的
從上面的代碼片段,我們已經知道,在對象創建之后,需要遍歷BBP列表,對對象進行處理。
這也就意味著,?BBP對象,必須在普通對象創建之前被創建?。
那么BBP都是在什么時候被創建的呢?
要回答這個問題,非常簡單,?我們只需要在CustomBeanPostProcessor的構造函數里打個斷點?(這下看到先學會用,再了解原理的好處了吧)
斷點進來,繼續利用調用棧,我們找尋到了AbstractApplicationContext的refresh()方法,這個方法里面調用了registerBeanPostProcessors方法,里頭就已經把BBP列表創建好了,而普通對象的創建,是在之后的finishBeanFactoryInitialization方法里執行的:
網上有個圖畫的特別好,很好的展示了BBP在Spring對象初始化流程的位置:
(看到BBP在哪了嗎?)
BBP的典型使用 - AOP
不知道大家在使用Spring AOP時,有沒有發現,帶有切面邏輯的對象,注入進來之后,都不是原來的對象了,比如下圖:
調試信息顯示,aspectService是一個…$$EnhanceBySpringCGlib的對象,這其實和Spring AOP用到的動態代理有關。
關于Spring AOP的原理,可以參考我之前的回答:?什么是面向切面編程AOP? - Javdroider Hong的回答 - 知乎
這也就意味著,?最終放進Spring容器的,必須是代理對象,而不是原先的對象?,這樣別的對象在注入時,才能獲得帶有切面邏輯的代理對象。
那么Spring是怎么做到這一點的呢?正是利用了這篇文章講到的BBP。
顯然,我只需要寫一個BBP,在postProcessBeforeInitialization或者postProcessAfterInitialization方法中,對對象進行判斷,看他需不需要織入切面邏輯,如果需要,那我就根據這個對象,生成一個代理對象,然后返回這個代理對象,那么最終注入容器的,自然就是代理對象了。
這個服務于Spring AOP的BBP,叫做?AnnotationAwareAspectJAutoProxyCreator?.
利用idea的diagram功能,可以看出它和BBP的關系:
具體的創建代理對象并返回的邏輯,在postProcessAfterInitialization方法中,大家自行欣賞。
可以說,如果沒有BBP,那么Spring AOP就只能叫AOP。
BBP是連接IOC和AOP的橋梁。
總結
這篇文章,主要通過對BBP的講解,串聯起之前講到的關于Spring的知識,希望能夠加深大家對Spring的理解。
最后,回到開頭提出的四個問題:
- BBP怎么用 —— 先學會怎么用,再去看原理
- BBP的觸發時機 —— 在整個Spring Bean初始化流程中的位置
- BBP自己又是什么時候被創建的?
- BBP是如何連接IOC和AOP的?
轉載于:https://www.cnblogs.com/yuxiang1/p/9199730.html
總結
以上是生活随笔為你收集整理的BeanPostProcessor —— 连接Spring IOC和AOP的桥梁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: docker系列之file基本操作
- 下一篇: Linux下 jenkins的安装