有小伙伴在學(xué)習(xí) Spring 源碼視頻的時候,看了松哥講的 BeanFactoryPostProcessor 的用法之后,提出了這樣一個問題:
圖片
圖片
我來跟大家補充一下這個問題的上下文:
我講了 BeanFactoryPostProcessor,分析了其原理,也講了具體的使用場景,一個典型的使用場景是我們在 XML 中定義 Bean 的時候,如果 Bean 的屬性是使用了 properties 文件占位符如 ${db.username} 這種,那么在 BeanFactoryPostProcessor 階段,就會對這個占位符進行處理,將其替換成真正的 value。然后我還順手給大家舉了一個例子,我在 XML 文件中定義 Bean 的時候,給 Bean 的某一個屬性設(shè)置 value 為 ^username,然后在 BeanFactoryPostProcessor 中,我將 ^username 改為某一個字符串。
小伙伴看了松哥講的內(nèi)容之后,也照著寫了一個,就是上面圖片中的代碼,不同的是,他是將 XML 配置改為了 Java 代碼配置,結(jié)果發(fā)現(xiàn)屬性 hok 并未變?yōu)?nbsp;NB,因此有了上述問題。
我覺得這個問題問的很好,給了小伙伴們一個從其他方面理解 Spring 的機會,這也是我前面一直強調(diào)的,這次的 Spring 視頻需要各位小伙伴一起發(fā)力,大家有關(guān)于 Spring 的任何問題都可以提,我負責(zé)通過源碼來回答你。
這個問題的分析,得先從 BeanDefinition 開始。在講 BeanFactoryPostProcessor 之前,松哥已經(jīng)和小伙伴們分析過 BeanDefinition 了,無論我們是通過 Java 代碼還是通過 XML 文件定義的 Bean 對象,在解析稱為 Bean 對象之前,得先解析成為 BeanDefinition,BeanDefinition 則有不同的分類,對于 XML 文件定義的 Bean,最終解析為 GenericBeanDefinition,而通過 @Bean 注解定義的 Bean 則解析為 ConfigurationClassBeanDefinition。
但是這兩個的處理原理顯然是有差異的。
對于 XML 定義的 Bean 來說,很明顯 XML 中的所有屬性都要先解析到 BeanDefinition 中,包括我們在 XML 中配置的 Bean 的各種屬性,這一步是在 Spring 容器 refresh 方法中構(gòu)建 BeanFactory 的時候完成的(obtainFreshBeanFactory 方法),這一步完成之后,在后面的步驟會去執(zhí)行容器中所有的 BeanFactoryPostProcessor(invokeBeanFactoryPostProcessors),此時就會把前面解析出來的 BeanDefinition 中帶有占位符的屬性給替換過來,最后在 refresh 方法中執(zhí)行 finishBeanFactoryInitialization 方法完成 Bean 的初始化。
按照上面這一套流程順序,占位符被解析成為正常字符串沒什么問題。
但是,如果是 @Bean 注解配置的 Bean,則會有所差異。
首先,@Bean 注解所標(biāo)記的方法要被解析為一個 ConfigurationClassBeanDefinition,這個過程本身是通過 ConfigurationClassPostProcessor 來完成的,而 ConfigurationClassPostProcessor 本質(zhì)上其實就是一個 BeanFactoryPostProcessor,換言之,@Bean 注解標(biāo)記的方法是在 BeanFactoryPostProcessor 中被解析為 ConfigurationClassBeanDefinition 的。ConfigurationClassBeanDefinition 這個 BeanDefinition 主要用來記錄 @Bean 注解所標(biāo)記的方法所屬的對象、方法的名稱、方法對象、方法參數(shù)、注解的參數(shù)等等信息,把這些信息記錄下來,將來在初始化 Bean 的時候,通過反射執(zhí)行目標(biāo)方法就可以了,即方法里邊的內(nèi)容是什么,ConfigurationClassBeanDefinition 其實并不關(guān)心。
最后則是和 XML 一樣,在 finishBeanFactoryInitialization 方法中完成 Bean 的初始化。
經(jīng)過上面分析,小伙伴們可以看到,通過 @Bean 注解定義的 Bean,我們?yōu)閷傩再x值是在方法內(nèi)部完成的,這些方法內(nèi)部的邏輯其實并未被解析到 BeanDefinition 中,顯然也沒有必要把方法內(nèi)部的邏輯解析到 BeanDefinition 上去,因此,通過 @Bean 注解定義的 Bean,如果屬性中使用了占位符,是無法通過 BeanFactoryPostProcessor 自動解析的。
好啦,現(xiàn)在小伙伴提出的問題大家伙都明白了吧?
本文鏈接:http://www.tebozhan.com/showinfo-26-17274-0.html答讀者問:BeanFactoryPostProcessor 似乎失效了?
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com