迴圈依賴三重境界之一:簡單迴圈依賴
juejin.im/post/5e1dcb…
迴圈依賴三重境界之二:@EnableAspectJAutoProxy
juejin.im/post/5dca47…
迴圈依賴三重境界之三:@Async
juejin.im/post/5e1e13…
為什麼會有這篇文章
網上迴圈依賴的文章數不勝數,代理的文章也數不勝數,但是迴圈依賴加上代理,就有點問題了,我想了一段時間才想通,所以記錄下來。
先看看網上說的迴圈依賴:
- 獲取單例A,A不存在
- 進行建立,放入快取
- 注入依賴B
- 發現B不在,建立B
- 注入A,發現快取中已經存在A,注入成功
- B初始化成功
- A初始化成功
再看看代理:
代理是通過一個後置處理器AbstractAutoProxyCreator處理的,無非就是做了個動態代理
那麼問題在哪兒?
我們仔細看下原始碼
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
**//這裡放入快取**
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
**//這裡注入屬性**
populateBean(beanName, mbd, instanceWrapper);
**//這裡動態代理**
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
複製程式碼
如果A和B都要進行代理,想想會怎麼樣?
- 建立A,發現沒有放入快取
- 注入屬性B
- 發現沒有B,建立B
- 初始化B,注入A,發現快取中有A,此時對A做代理,得到代理物件A1
- B中有了代理物件A1
- 對B做代理,得到代理物件B1,此時B1中有A1
- 對A做代理,得到代理物件A2
等等,A2中有B1,B1中有A1,這好像不是迴圈依賴啊,是不是漏了什麼東西?
啟個專案debug
在B中對A做的代理,拿到的是
然後對B做代理,拿到的是 再返回到A的初始化過程中 代理A之前 代理A之後有問題,A居然沒有被代理! 重新debug發現,在B拿到A的代理物件時,把A放入到了一個map中
在最外層的A初始化時,再進行代理,發現A已經代理過了,就不再對A進行代理了
我們繼續往下看
可以發現,最終暴露出來的並不是在外層進行了一頓注入/後置處理操作的A,而是從快取中拿到的A。(不代理時也是如此,不贅述了)
那麼現在問題變成了: B從快取中建立A的代理物件A1,注入,對B進行代理,這樣,B中有了A1,可是A1好像沒有依賴上B?
這個問題其實和代理有關,我們在產生代理物件A1的時候,將目標物件A的例項傳進去,將B的代理物件B1注入A之後,產生的代理物件A1也有了B的代理物件B1。可以看看程式碼是怎麼做的。
B從快取中拿A,A的生產過程: 此時目標物件中還沒有B,因為還沒有populate注入
在populate之後,可以看到A的代理物件A1的target中已經有了B的代理物件B1,此時A1中有B1,B1中有A1,迴圈依賴+代理,大功告成。總結流程
原圖:www.processon.com/view/link/5…
補充:
今天跟朋友又聊到了這個問題,複習一下,順便記錄一下,非迴圈依賴模式下的代理是這樣的
A----B----A,B中代理A時的代理是這樣的
可以看到是有些不同的