迴圈依賴三重境界之二:@EnableAspectJAutoProxy

Wayne_Kdl發表於2019-11-12

迴圈依賴三重境界之一:簡單迴圈依賴
juejin.im/post/5e1dcb…

迴圈依賴三重境界之二:@EnableAspectJAutoProxy
juejin.im/post/5dca47…

迴圈依賴三重境界之三:@Async
juejin.im/post/5e1e13…

為什麼會有這篇文章

網上迴圈依賴的文章數不勝數,代理的文章也數不勝數,但是迴圈依賴加上代理,就有點問題了,我想了一段時間才想通,所以記錄下來。

先看看網上說的迴圈依賴:

  1. 獲取單例A,A不存在
  2. 進行建立,放入快取
  3. 注入依賴B
  4. 發現B不在,建立B
  5. 注入A,發現快取中已經存在A,注入成功
  6. B初始化成功
  7. 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都要進行代理,想想會怎麼樣?

  1. 建立A,發現沒有放入快取
  2. 注入屬性B
  3. 發現沒有B,建立B
  4. 初始化B,注入A,發現快取中有A,此時對A做代理,得到代理物件A1
  5. B中有了代理物件A1
  6. 對B做代理,得到代理物件B1,此時B1中有A1
  7. 對A做代理,得到代理物件A2

等等,A2中有B1,B1中有A1,這好像不是迴圈依賴啊,是不是漏了什麼東西?

啟個專案debug

在B中對A做的代理,拿到的是

迴圈依賴三重境界之二:@EnableAspectJAutoProxy
然後對B做代理,拿到的是

迴圈依賴三重境界之二:@EnableAspectJAutoProxy
再返回到A的初始化過程中 代理A之前

迴圈依賴三重境界之二:@EnableAspectJAutoProxy
代理A之後

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

有問題,A居然沒有被代理! 重新debug發現,在B拿到A的代理物件時,把A放入到了一個map中

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

在最外層的A初始化時,再進行代理,發現A已經代理過了,就不再對A進行代理了

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

我們繼續往下看

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

可以發現,最終暴露出來的並不是在外層進行了一頓注入/後置處理操作的A,而是從快取中拿到的A。(不代理時也是如此,不贅述了)

那麼現在問題變成了: B從快取中建立A的代理物件A1,注入,對B進行代理,這樣,B中有了A1,可是A1好像沒有依賴上B?

這個問題其實和代理有關,我們在產生代理物件A1的時候,將目標物件A的例項傳進去,將B的代理物件B1注入A之後,產生的代理物件A1也有了B的代理物件B1。可以看看程式碼是怎麼做的。

B從快取中拿A,A的生產過程: 此時目標物件中還沒有B,因為還沒有populate注入

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

迴圈依賴三重境界之二:@EnableAspectJAutoProxy
在populate之後,可以看到A的代理物件A1的target中已經有了B的代理物件B1,此時A1中有B1,B1中有A1,迴圈依賴+代理,大功告成。

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

總結流程

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

原圖:www.processon.com/view/link/5…

補充:

今天跟朋友又聊到了這個問題,複習一下,順便記錄一下,非迴圈依賴模式下的代理是這樣的

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

A----B----A,B中代理A時的代理是這樣的

迴圈依賴三重境界之二:@EnableAspectJAutoProxy

可以看到是有些不同的

相關文章