參考博客原文地址:
https://www.jb51.net/article/168398.htm
https://www.cnblogs.com/mianteno/p/10692633.html
http://www.pianshen.com/article/4112200143/
1.構造器依賴循環
代碼示例:
@Component
public class A {
private B b;
@Autowired
public A(B b) {
this.b=b;
}
}
@Component
public class B {
private C c;
@Autowired
public B(C c) {
this.c = c;
}
}
@Component
public class C {
private A a;
@Autowired
public C(A a) {
this.a=a;
}
}
啟動運行后運行結果:
可以看到異常的信息:
//org.springframework.beans.factory.BeanCurrentlyInCreationException
public BeanCurrentlyInCreationException(String beanName) {
super(beanName,
"Requested bean is currently in creation: Is there an unresolvable circular reference?");
}
這種循環依賴沒有什么解決辦法,因為JVM虛擬機在對類進行實例化的時候,需先實例化構造器的參數,而由於循環引用這個參數無法提前實例化,故只能拋出錯誤。
2.屬性注入依賴循環
代碼示例:
@Component
public class A {
@Autowired
private B b;
public A() {
System.err.println(b);
}
}
@Component
public class B {
@Autowired
private C c;
public B() {
System.err.println(c);
}
}
@Component
public class C {
@Autowired
private A a;
public C() {
System.err.println(a);
}
}
啟動運行后運行結果:
//程序正常啟動,輸出如下
null
null
null
結論:
Spring通過將實例化后的對象提前暴露給Spring容器中的singletonFactories,解決了循環依賴的問題
3.源碼分析 構造器循環依賴異常步驟及原因:
創建一個Bean的過程是:實例化->初始化(屬性)->放到緩存中,如下圖
這張圖是核心
getSingleton源碼:
//首次創建的beanName放入singletonsCurrentlyInCreation中
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
構造器循環依賴,在初始化C時,需要先實例化A,但是A已經在singletonsCurrentlyInCreation有預實例化的記錄了,所以此處拋出異常。
public BeanCurrentlyInCreationException(String beanName) {
super(beanName,
"Requested bean is currently in creation: Is there an unresolvable circular reference?");
}
源碼分析 Spring如何解決屬性注入 依賴循環問題:
//相關類
org.springframework.beans.factory.support.DefaultListableBeanFactory
org.springframework.beans.factory.support.AbstractBeanFactory
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
可以看到,在實例化后,Bean被添加到singletonFactories中了,所以可以獲取到Bean實例,解決了屬性循環依賴問題
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
4.最終總結:
構造器循環依賴:沒有什么解決辦法,因為JVM虛擬機在對類進行實例化的時候,需先實例化構造器的參數,而由於循環引用這個參數無法提前實例化,故只能拋出錯誤。
屬性循環依賴:Spring通過將實例化后的對象提前暴露給Spring容器中的singletonFactories,解決了循環依賴的問題