高頻面試題:Spring 如何解決循環依賴?


https://www.cnblogs.com/zzq6032010/p/11406405.html

 

 通過上面的步驟可以看出這三個map的優先級。其中singletonObjects里面存放的是初始化之后的單例對象;earlySingletonObjects中存放的是一個已完成實例化未完成初始化的早期單例對象;而singletonFactories中存放的是ObjectFactory對象,此對象的getObject方法返回值即剛完成實例化還未開始初始化的單例對象。所以先后順序是,單例對象先存在於singletonFactories中,后存在於earlySingletonObjects中,最后初始化完成后放入singletonObjects中

        可以看到,在構造器執行的時候未完成屬性的注入,而在調用方法的時候已經完成了注入。下面就一起看看Spring內部是在何時完成的屬性注入,又是如何解決的循環依賴。

 

至此,Spring循環依賴的總結分析結束,一句話來概括一下:Spring通過將實例化后的對象提前暴露給Spring容器中的singletonFactories,解決了循環依賴的問題

 

 protected void addSingleton(String beanName, Object singletonObject) {
2         synchronized (this.singletonObjects) {
3             this.singletonObjects.put(beanName, singletonObject);//添加單例對象到map中
4             this.singletonFactories.remove(beanName);//從早期暴露的工廠中移除,此map在解決循環依賴中發揮了關鍵的作用
5             this.earlySingletonObjects.remove(beanName);//從早期暴露的對象map中移除
6             this.registeredSingletons.add(beanName);//添加到已注冊的單例名字集合中
7         }
8     }

 

 

 

 

關於Spring bean的創建,其本質上還是一個對象的創建,既然是對象,讀者朋友一定要明白一點就是,一個完整的對象包含兩部分:當前對象實例化和對象屬性的實例化。

 

在Spring中,對象的實例化是通過反射實現的,而對象的屬性則是在對象實例化之后通過一定的方式設置的。

 

 

  • Spring是通過遞歸的方式獲取目標bean及其所依賴的bean的;
  • Spring實例化一個bean的時候,是分兩步進行的,首先實例化目標bean,然后為其注入屬性。

結合這兩點,也就是說,Spring在實例化一個bean的時候,是首先遞歸的實例化其所依賴的所有bean,直到某個bean沒有依賴其他bean,此時就會將該實例返回,然后反遞歸的將獲取到的bean設置為各個上層bean的屬性的。

 

 

簡言之,兩個池子:一個成品池子,一個半成品池子。能解決循環依賴的前提是:spring開啟了allowCircularReferences,那么一個正在被創建的bean才會被放在半成品池子里。在注入bean,向容器獲取bean的時候,優先向成品池子要,要不到,再去向半成品池子要。

出現循環依賴一定是你的業務設計有問題。高層業務和底層業務的划分不夠清晰,一般,業務的依賴方向一定是無環的,有環的業務,在后續的維護和拓展一定非常雞肋

 

構造注入無法解決循環依賴,而spring的三級緩存的存在是的,setter注入不存在循環依賴
 
的確,工程問題和理論是兩碼事,工程內大家怎么方便怎么做,spring官方推構造器注入,在國外推廣得也很不錯,但是一到國內,受大量二流教程和培訓班的影響,大家只會怎么方便怎么做,現在80%以上的人還是@Autowired字段的,還有為數不少的在用@Resource。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM