Spring循環依賴的問題

 
什麼是循環依賴?就是兩個Bean相互引用,比如用@Autowire 相互注入。
 
那麼Spring是如何解決這個問題的呢?在Bean還未完全實例化前(類只實例化了一部分),將bean提前暴露出來,可以被其他Bean引用。
 
源碼解析:
 
問題1:什麼情況下需要提前暴露?
 
Spring託管的bean是通過getBean()–>doCreateBean()創建的。
 
正常情況下,單例模式,第一次調用getBean單例初始化完成後,直接放入cache了,後面再次調用直接從cache拿,不用走doCreateBean 了。
 
0
 
 
當有循環依賴時候,第二次調用getBean程式碼earlySingletonExposure就會=true,那麼
就會觸發行提前暴露bean的邏輯。
 
關鍵程式碼:addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
 
AbstractAutowireCapableBeanFactory.doCreateBean();
 
0
 
 
 
問題2: 提前暴露出去的對象是指定類型的Bean的實例本身嗎?
不是的,是一個ObjectFactory用於創建該Bean實例 。因為Spring AOP機制,bean在後續實例化過程中可能會被BeanPostProcess處理,生成一個Proxy對象。
 
問題3: 是怎麼提前暴露出去的?
其實很簡單,遍歷所有的BeanPostProcessor ,看是不是SmartInstantiationAwareBeanPostProcessor 對象(該介面是Spring AOP的頂級介面),不是(不需要AOP)直接返回原始bean。SmartInstantiationAwareBeanPostProcessor 提供了一個後門getEarlyBeanReference,該方法提前先調用了proxy bean的生成方法 wrapIfNecessary(),也就是說,AOP提前切入了。
0
 
 
問題4: 提前暴露出去的bean和最終生成的bean是同一個嗎?
SmartInstantiationAwareBeanPostProcessor 介面做了強制規定,要麼是同一個proxy對象,要麼直接放回原始bean(不需要AOP的類)。
0
 
下面用AbstractAutoProxyCreator這個具體實現類的程式碼作進一步說明。 方法postProcessAfterInitialization() 加了一個判斷,如果之前調用了getEarlyBeanReference(),完成了AOP,這裡就不重複調用wrapIfNecessary()了(只是從earlyProxyReferences 做了remove),從而保證是同一個proxy對象。
0
 
 
問題5:很多文檔說的循環依賴是通過三級快取解決的,這個說法是咋回事?
 
上面詳細介紹了singletonFactories 怎麼暴露出去的,三級快取就是DefaultSingletonBeanRegistry類裡面的三個map,快取核心邏輯見下段程式碼,先找singletonObjects,找不到再從earlySingletonObjects找,還是沒有直接用singletonFactories 工廠創建(裡面對singletonObjects加了鎖,防止並發錯誤)。
0
 
程式碼實踐:
為了證明以上說法,我們簡單寫一點程式碼加以驗證。
程式碼://gitee.com/zfj321/spring-sourcecode-study
然後在下面位置打一個斷點,進行跟蹤。
0
 
 
參考資料: