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的時候,優先向成品池子要,要不到,再去向半成品池子要。
出現循環依賴一定是你的業務設計有問題。高層業務和底層業務的划分不夠清晰,一般,業務的依賴方向一定是無環的,有環的業務,在后續的維護和拓展一定非常雞肋