1. 程式人生 > >Spring迴圈依賴的問題

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   程式碼實踐: 為了證明以上說法,我們簡單寫一點程式碼加以驗證。 程式碼:https://gitee.com/zfj321/spring-sourcecode-study 然後在下面位置打一個斷點,進行跟蹤。 0     參考資料: https://programmersought.com/article/2719427598/ https://blog.xieyangzhe.com/archives/882 https://programming.vip/keywords/java       &nbs