答讀者問:BeanFactoryPostProcessor 似乎失效了?
來源:江南一點雨
有小夥伴在學習 Spring 原始碼影片的時候,看了松哥講的 BeanFactoryPostProcessor 的用法之後,提出了這樣一個問題:
我來跟大家補充一下這個問題的上下文:
我講了 BeanFactoryPostProcessor,分析了其原理,也講了具體的使用場景,一個典型的使用場景是我們在 XML 中定義 Bean 的時候,如果 Bean 的屬性是使用了 properties 檔案佔位符如 ${db.username}
這種,那麼在 BeanFactoryPostProcessor 階段,就會對這個佔位符進行處理,將其替換成真正的 value。然後我還順手給大家舉了一個例子,我在 XML 檔案中定義 Bean 的時候,給 Bean 的某一個屬性設定 value 為 ^username,然後在 BeanFactoryPostProcessor 中,我將 ^username 改為某一個字串。
小夥伴看了松哥講的內容之後,也照著寫了一個,就是上面圖片中的程式碼,不同的是,他是將 XML 配置改為了 Java 程式碼配置,結果發現屬性 hok
並未變為 NB
,因此有了上述問題。
我覺得這個問題問的很好,給了小夥伴們一個從其他方面理解 Spring 的機會,這也是我前面一直強調的,這次的 Spring 影片需要各位小夥伴一起發力,大家有關於 Spring 的任何問題都可以提,我負責透過原始碼來回答你。
問題分析
這個問題的分析,得先從 BeanDefinition 開始。在講 BeanFactoryPostProcessor 之前,松哥已經和小夥伴們分析過 BeanDefinition 了,無論我們是透過 Java 程式碼還是透過 XML 檔案定義的 Bean 物件,在解析稱為 Bean 物件之前,得先解析成為 BeanDefinition,BeanDefinition 則有不同的分類,對於 XML 檔案定義的 Bean,最終解析為 GenericBeanDefinition,而透過 @Bean 註解定義的 Bean 則解析為 ConfigurationClassBeanDefinition。
但是這兩個的處理原理顯然是有差異的。
對於 XML 定義的 Bean 來說,很明顯 XML 中的所有屬性都要先解析到 BeanDefinition 中,包括我們在 XML 中配置的 Bean 的各種屬性,這一步是在 Spring 容器 refresh 方法中構建 BeanFactory 的時候完成的(obtainFreshBeanFactory 方法),這一步完成之後,在後面的步驟會去執行容器中所有的 BeanFactoryPostProcessor(invokeBeanFactoryPostProcessors),此時就會把前面解析出來的 BeanDefinition 中帶有佔位符的屬性給替換過來,最後在 refresh 方法中執行 finishBeanFactoryInitialization 方法完成 Bean 的初始化。
按照上面這一套流程順序,佔位符被解析成為正常字串沒什麼問題。
但是,如果是 @Bean 註解配置的 Bean,則會有所差異。
首先,@Bean 註解所標記的方法要被解析為一個 ConfigurationClassBeanDefinition,這個過程本身是透過 ConfigurationClassPostProcessor 來完成的,而 ConfigurationClassPostProcessor 本質上其實就是一個 BeanFactoryPostProcessor,換言之,@Bean 註解標記的方法是在 BeanFactoryPostProcessor 中被解析為 ConfigurationClassBeanDefinition 的。ConfigurationClassBeanDefinition 這個 BeanDefinition 主要用來記錄 @Bean 註解所標記的方法所屬的物件、方法的名稱、方法物件、方法引數、註解的引數等等資訊,把這些資訊記錄下來,將來在初始化 Bean 的時候,透過反射執行目標方法就可以了,即方法裡邊的內容是什麼,ConfigurationClassBeanDefinition 其實並不關心。
最後則是和 XML 一樣,在 finishBeanFactoryInitialization 方法中完成 Bean 的初始化。
經過上面分析,小夥伴們可以看到,透過 @Bean 註解定義的 Bean,我們為屬性賦值是在方法內部完成的,這些方法內部的邏輯其實並未被解析到 BeanDefinition 中,顯然也沒有必要把方法內部的邏輯解析到 BeanDefinition 上去,因此,透過 @Bean 註解定義的 Bean,如果屬性中使用了佔位符,是無法透過 BeanFactoryPostProcessor 自動解析的。
好啦,現在小夥伴提出的問題大傢伙都明白了吧?
以上的分析中,方法的具體邏輯在 Spring 原始碼中都有詳細講解,所以這裡我只是和大家梳理了思路,具體實現小夥伴可以參考我們的原始碼影片。
歡迎各位小夥伴在學習過程中繼續提出高質量問題,一起把這套 Spring 原始碼教程做紮實了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2993493/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 冴羽答讀者問:怎麼平衡工作與生活?
- 答讀者問(21):一個研二學生有關論文的相關疑問及答覆
- 冴羽答讀者問:你是怎麼理解知行合一的?
- 《實用Common Lisp程式設計》作者Peter Seibel答讀者問Lisp程式設計
- 冴羽答讀者問:如何學習更有計劃性、提升更穩更快?
- 冴羽答讀者問:功利性學習的心態,你是否也會有?
- 冴羽答讀者問:如何在工作中打造影響力,帶動同事?
- MySQL 實戰 | 08 懵逼,可重複讀好像失效了?MySql
- Spring原始碼解讀之BeanFactoryPostProcessor的處理Spring原始碼Bean
- 問答營銷的流程和特點——以使用者思維做問答營銷
- 基於CNN的閱讀理解式問答模型:DGCNNCNN模型GC
- 問了幾人,MySQL changebuffer 這點都沒答對MySql
- 答讀者問(1):非模式物種找marker;如何根據marker定義細胞型別模式型別
- 冴羽答讀者問:如果有機會,你會選擇脫產學習深造嗎?
- css失效問題CSS
- 有名訊號量實現讀者-寫者問題(讀者優先)
- Redis叢集高頻問答,連夜肝出來了Redis
- 答讀者疑問:為什麼我的 manifest.json 檔案無法正確被載入試讀版JSON
- Web 面試問答Web面試
- 問答專案
- 基礎問答
- 提問與問答技巧
- 冴羽答讀者問:除程式碼外,就沒別的優先順序很高的愛好了嗎?
- MyBatis order by失效問題MyBatis
- 外掛失效問題
- 操作熱點問答:醫療系統被攻擊了怎麼辦?
- Spring的BeanFactoryPostProcessor介面SpringBean
- oracle資料庫版讀者寫者問題Oracle資料庫
- 讀寫者問題-java實現Java
- https問答篇HTTP
- Redux:自問自答Redux
- QTP問與答(轉)QT
- Unicode 問答集Unicode
- C#問答 (轉)C#
- [ 答朋友問] same namespace ?namespace
- Spring Boot 面試,一個問題你就答不上來了Spring Boot面試
- 用OceanBase試了一下ChatGPT開源文件問答助手ChatGPT
- 老牌問答網站“雅虎問答”近日宣佈正式關站NRE網站