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