循環依賴
在使用Spring時,如果主要採用基於構造器
的依賴注入方式,則可能會遇到循環依賴的情況,簡而言之就是Bean A
的構造器依賴於Bean B
,Bean B
的構造器又依賴於Bean A
。在這種情況下Spring會在編譯時拋出BeanCurrentlyInCreationException
。
Class A
@Component
public class ClassA {
private ClassB classB;
@Autowired
public ClassA(ClassB classB) {
this.classB = classB;
}
public void printClass() {
System.out.println("Class A = " + this);
System.out.println("Class B = " + classB);
}
}
Class B
@Component
public class ClassB {
private ClassA classA;
@Autowired
public ClassB(ClassA classA) {
this.classA = classA;
}
public void printClass() {
System.out.println("Class A = " + classA);
System.out.println("Class B = " + this);
}
}
測試
@ContextConfiguration(classes = {ClassA.class, ClassB.class})
@RunWith(SpringRunner.class)
public class MyTest {
@Autowired
private ClassA classA;
@Autowired
private ClassB classB;
@Test
public void name() {
classA.printClass();
classB.printClass();
}
}
原因
這時候運行測試就會發現拋出了BeanCurrentlyInCreationException
異常。產生這種情況的原因是,Spring在創建Bean時,會首先實例化對象,然後再注入依賴。假設Spring首先創建Class A
,那麼就會發現在構造器裏有Class B
的依賴,所以就會轉去創建Class B
,又在Class B
的構造器裏發現了對Class A
的依賴,而此時Class A
是還未初始化完的,因此又會轉去創建Class A
,這樣就陷入了死循環。
解決方法
換成基於setter
的依賴注入即可解決這個問題。因爲基於setter
的依賴注入會首先調用默認構造函數來實例化對象,然後再調用setter
實現依賴注入。這樣在對象實例化的階段就沒有了任何依賴,因此Class A
實例化完成後再調用Class B
,Class B
實例化完成後開始設值,而這時Class A
已經是實例化完成了的,所以可以成功引用到Class A
。