spring源碼分析——三級緩存與循環依賴的實現


 

  在使用spring框架開發時,會出現類A 依賴  類B  ,類B 又依賴 類A的情況,就是循環依賴了,那么spring容器是怎么處理的呢

在看循環依賴之前我們先來看一下spring中的三級緩存。

一:spring容器中的緩存

spring容器對對象的注冊維護,主要是通過DefaultSingletonBeanRegistry來實現的,這個類提供了一些存儲以及獲取的方法,我們首先類分析一下這個類

 

 

下面是三級緩存集合:

 

 

下面看一下這個類里基本的方法:

注冊單例bean:

 

 

放入一級緩存中:

 

 放入三級緩存中:

 

 

獲取單例對象的過程:

 

 

獲取單例bean的核心邏輯:

 

 

 

二:spring循環依賴的源碼分析 

1:單例bean屬性的循環依賴

准備工作:創建TestA類,依賴TestB類,然后TestB類 又反過來依賴 TestA 類

@Component
public class TestA {

	@Autowired
	private TestB testB;

}

  

@Component
public class TestB {

	@Autowired
	private TestA testA;

}

  

我們來分析一下這種屬性循環依賴的情況

我們從AbstractBeanFactory類的doGetBean看起

 

 

如果緩存中不存在,那么就調用getSingleton實例化TestA對象:

 

 

 

 

在堆內存中開辟空間,創建對象后,如果單例bean,運行循環依賴,那么放入三級緩存中。

 

 

設置屬性:

 

 

設置屬性testB

 

 

具體Autowired的過程這里不再分析,可以看上面章節分析Autowired注入的過程,在AutowiredAnnotationBeanPostProcessor方法中會涉及到getBean(testB),然后又會觸發

testB實例化的過程,

 

 

遞歸回到最開始testA的實例化過程,流程和之前實例化testA一樣,最后也是走到設置屬性:

 

 

testB實例化過程中,設置屬性testA

 

 

又會走到getBean實例化testA,這時又遞歸回到了DefaultListableBeanFactory的getBean方法

 

 

 

 

 

 

然后返回一個沒有初始化的testA對象,然后testB設置屬性成功,初始化完成,緩存並返回對象,

 

又回到了testA對象設置屬性的時候,然后testA設置屬性完成,到這里單例的循環依賴就成功的解決了。

測試代碼:

 

 運行結果:

 通過結果可以看出spring是支持單例的屬性的循環依賴的

2:單例bean 構造器的循環依賴

 准備工作:

@Component
public class TestA {

	private TestB testB;

	@Autowired
	public TestA(TestB testB){
		this.testB = testB;
	}

}

  

@Component
public class TestB {

	private TestA testA;

	@Autowired
	public TestB(TestA testA){
		this.testA = testA;
	}

}

 

運行一下:

 

 

 

 

拋出異常:從運行結果可以看出,首先實例化testA,創建testA實例的時候,發現是有參數構造函數,所以尋找參數testB,然后getBean,實例化testB,

發現testB也是有參數構造函數,所以尋找參數testA,getBean(testA),由於testA還沒有創建,所以沒法放入集合中標記,拋出異常。

總結:spring不支持構造器的循環依賴

 

3:prototype類型非單例循環依賴

doGetBean方法中:

 

 

准備工作:

@Component
@Scope("prototype")
public class TestA {

	@Autowired
	private TestB testB;

}

  

@Component
@Scope("prototype")
public class TestB {

	@Autowired
	private TestA testA;

}

  

運行測試用例:

 

 

從運行結果可以看出,spring容器不支持prototype類型的循環依賴。

 

4:如果相互依賴的兩個類,一個類TestA是非單例,另一個類TestB單例,會怎樣?

@Component
@Scope("prototype")
public class TestA {

	@Autowired
	private TestB testB;

}

  

@Component
//@Scope("prototype")
public class TestB {

	@Autowired
	private TestA testA;

}

  

運行結果:

 

 

正常運行,沒有拋出異常。

因為spring預實例化只會實例化非單例的bean,那么TestB會先實例化,設置屬性時發現依賴TestA ,然后實例化TestA,

TestA是非單例,創建bean,設置屬性時,發現依賴TestB,getBean(testB),實例化TestB,這時緩存中已經存在testB,從

三級緩存中拿到testB,TestA實例化完成,返回對象,TestB實例化完成。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM