Spring迴圈依賴的問題
阿新 • • 發佈:2020-10-03
什麼是迴圈依賴?就是兩個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
然後在下面位置打一個斷點,進行跟蹤。
參考資料:
https://programmersought.com/article/2719427598/
https://blog.xieyangzhe.com/archives/882
https://programming.vip/keywords/java
&nbs