Spring 循環依賴解決方案
1.Spring創建Bean主要分為兩個步驟,創建原始Bean對象,接着去填充對象屬性喝初始化。采用refresh()
里面的11個修飾方法
2.每次創建bean之前,都會去緩存查看一下有沒有該bean,因為是單例的,只能有一個。
3.當我們創建beanA的原始對象以后,並且把它放到三級緩存中,接下來就准備填充屬性,這個時候發現依賴beanB,接着又去創建beanB
同樣的流程,創建完beanB以后填充屬性的時候又發現他依賴beanA又是同樣的流程。
不同的是:
創建beanB的時候,這個時候可以再三級緩存中查詢剛放進去的原始對象beanA(未填充數據的beanA),所以不需要繼續創建,用它來注入beanB, 完成beanB的創建
既然beanB創建好了,放到一級緩存,所以剛放進去beanA就可以完成填充屬性的步驟了,接着執行完剩下的邏輯,閉環完成,最終beanA喝beanB都在一級緩存中。
三級緩存流程:
查詢流程:
Spring中解決循環依賴是依賴Bean的“中間態”這個概念,這個中間態指的是已經實例化了,但是還沒有初始化狀態---》俗稱:半成品
實例化的過程又是通過構造器創建的,如果A沒有創建好,是不可能提前曝光的,所以構造器的循環依賴無法解決。
但是Spring中為了解決單例下的循環依賴問題,使用了三級緩存。
一級緩存是單例池(singletoObjects)
二級緩存是提前曝光對象(earlySingletonObjects)
三級緩存是提前曝光工廠(singletoFactories)
假設A、B循環引用,實例化A的時候將其放入三級緩存中,接着填充屬性,發現依賴了B,同樣的流程也是實例化后將beanB放入三級緩存,
接着去填充屬性的時候,發現了beanB依賴了A,這個時候從緩存中去查詢早期暴露再工廠的A:
- 沒有AOP代理的化,直接將A的原始狀態注入B,完成B的初始化后,接着屬性填充和初始化,這個時候B已經完成,就去完成剩下A的步驟,
- 有AOP代理的話,就進行AOP處理獲取代理后的對象A,注入B,走剩下流程。