spring學習之源碼分析--bean的建立以及以前的文章,都提到了循環依賴,那此次我們來看看spring是如何解決循環依賴的。
在spring學習之注入中,咱們看到了兩種的注入方式,一個是構造函數注入,一個是setter注入。咱們分別看看這兩種方式,各是什麼樣的狀況。spring
TestA的構造函數注入了TestB,TestB的構造函數注入了TestA。segmentfault
public class TestA { private TestB testB; public TestA(@Autowired TestB testB) { this.testB = testB; } } public class TestB { private TestA testA; public TestB(@Autowired TestA testA) { this.testA = testA; } }
測試代碼函數
@Test public void testCircleByConstructor() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(TestA.class, TestB.class); context.refresh(); }
運行結果
主要的錯誤以下:源碼分析
Error creating bean with name 'testA': Requested bean is currently in creation: Is there an unresolvable circular reference
下面看看整個流程圖:
學習
下面看看setter注入的時候,是怎麼處理的測試
TestC的setter注入了TestD,TestD的setter注入了TestC。跟上面構造函數不一樣的是,這邊是無參構造,因此能夠先實例化,再進行屬性設置。this
public class TestC { @Autowired private TestD testD; } public class TestD { @Autowired private TestC testC; }
測試代碼spa
@Test public void testCircleBySet() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(TestC.class, TestD.class); context.refresh(); }
下面看看整個流程圖:
prototype
TestE的setter注入了TestF,TestF的setter注入了TestE。跟上面不一樣的是,這邊是Scope是prototype。
由於是多例的,因此容器初始化的時候,並不會實例化,只能咱們本身調用的時候實例化。code
@Scope("prototype") public class TestE { @Autowired private TestF testF; } @Scope("prototype") public class TestF { @Autowired private TestE testE; }
測試代碼
@Test public void testCircleByPrototype() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(TestE.class, TestF.class); context.refresh(); context.getBean("testE"); }
運行結果:
主要的錯誤以下:
Error creating bean with name 'testE': Requested bean is currently in creation: Is there an unresolvable circular reference
下面看看整個流程圖:
多例的判斷,是經過prototypesCurrentlyInCreation來的,建立前設值進去,建立後移除,若是循環依賴,就會出現還沒移除又設值的狀況,就拋異常了。
建立bean以前,會經過isDependent判斷是否循環依賴,沒有循環依賴經過registerDependentBean註冊依賴