在Spring中如何處理循環(huán)依賴問題
Spring如何處理循環(huán)依賴
解決的關(guān)鍵就在于提前曝光未完全創(chuàng)建的bean。
在Spring中創(chuàng)建Bean分為三步
- 實例化,createBeanInstance,即new一個bean對象。
- 屬性填充,populateBean,即往bean對象中set屬性值。
- 初始化,initializeBean。
循環(huán)依賴的解決思路
- 先創(chuàng)建A的bean實例,此時的A是不完整的,因為沒有屬性填充(即B依賴沒有注入),此時用一個Map保存不完整的A,
- 再創(chuàng)建B,B需要注入A,所以可以從Map中得到不完整的A,此時B就完整了,然后A就可以注入B了。
在Spring中,只有同時滿足以下兩點才能解決循環(huán)依賴的問題。
1.依賴的bean必須都是單例。
- 因為如果是原型模式的話是需要創(chuàng)建一個新的對象,創(chuàng)建A1的時候,需要創(chuàng)建A1的依賴B1
- 那么在創(chuàng)建B1的時候,又需要創(chuàng)建B1的依賴A2,這樣就要創(chuàng)建B2,A3,B3……,進入無限的創(chuàng)建對象的過程
2.依賴注入的方式,不能全是構(gòu)造函數(shù)注入。
- 如果全是構(gòu)造函數(shù)注入,即A(B b) ,那么表明在創(chuàng)建A的Bean的實例的時候,就需要得到B,那么此時就要創(chuàng)建B的bean實例,但是B也是要在構(gòu)造函數(shù)中注入A,即B(A a),此時B需要在Map中找到不完整的A,但是發(fā)現(xiàn)找不到,因為A的Bean實體還沒創(chuàng)建完(還在等著B)。
- 注意:Spring容器是按照字母的順序創(chuàng)建 Bean的,因此循環(huán)依賴中,字母排在前面的Bean不能采用構(gòu)造函數(shù)注入。
Sping解決循環(huán)依賴全流程
首先了解Spring bean相關(guān)的三個Map
singletonObject,存放所有創(chuàng)建完畢的單例bean(完整的bean,即已經(jīng)完成實例化并進行屬性填充)。earlySingletonObjects,存放僅完成實例化,但未進行屬性填充和初始化的Bean。singletonfactories,存放能創(chuàng)建Bean的工廠,通過這個工廠能獲得bean,延遲bean生成,工廠生成的bean會放到earlySingletonObjects中。
在實例化bean后,Spring是不知道當前bean有沒有循環(huán)依賴的,它會義無反顧的往singletonfactories中存放當前bean的工廠,這個步驟就是提前曝光
然后開始屬性注入,此時bean A發(fā)現(xiàn)要注入bean B,所以請執(zhí)行g(shù)etBean(B)
- 先去singletonObject里找有沒有,如果有則進行返回
- 如果沒有,則判斷Bean是否在創(chuàng)建中,如果不在創(chuàng)建中,則返回null
- 如果在創(chuàng)建中,則去earlySingletonObjects找,如果有則進行返回
- 如果沒有,則去singletonfactories找到這個bean的工廠,通過工廠去創(chuàng)建bean,并存放到earlySingletonObjects中
- 如果singletonfactories沒有找到bean的工廠就返回null
- 如果返回null,說明bean還沒有創(chuàng)建,這個時候會先把這個bean標記為創(chuàng)建中,再調(diào)用doCreateBean(即,實例化,屬性填充,初始化三個步驟)
此時就到了B這個bean屬性注入的步驟了,調(diào)用了getBean(A),A此時在singletonfactories中找到提前暴露的工廠的到了A,然后把A從singletonfactories中刪除,放到earlySingletonObjects中。
此時B屬性注入成功,然后進行初始化,最后B存放到singletonObject中。
此時又回到了A注入B的地方,完成了對B的注入,然后A也從earlySingletonObjects刪除,存放到singletonObject中。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBatch從入門到精通之StepScope作用域和用法詳解
這篇文章主要介紹了SpringBatch從入門到精通之StepScope作用域和用法詳解,主要包括IOC容器中幾種bean的作用范圍以及可能遇到的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-05-05
java使用MulticastSocket實現(xiàn)基于廣播的多人聊天室
這篇文章主要為大家詳細介紹了java使用MulticastSocket實現(xiàn)基于廣播的多人聊天室,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01
SpringBoot響應處理之以Json數(shù)據(jù)返回的實現(xiàn)方法
這篇文章主要介紹了SpringBoot整合Web開發(fā)其中Json數(shù)據(jù)返回的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-09-09
Java如何導出數(shù)據(jù)庫中的所有數(shù)據(jù)表到指定文件夾
這篇文章主要介紹了Java導出數(shù)據(jù)庫中的所有數(shù)據(jù)表到指定文件夾,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06

