Spring原始碼解析之迴圈依賴
阿新 • • 發佈:2022-05-08
看個例子
CircularA類
@Service
public class CircularA {
@Autowired
private CircularB circularB;
public CircularB getCircularB() {
return circularB;
}
}
CircularB類
@Service public class CircularB { @Autowired private CircularA circularA; public CircularA getCircularA() { return circularA; } }
測試方法
@Test public void test3() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext("cn.com.dq"); CircularA circularA = (CircularA) applicationContext.getBean("circularA"); System.out.println(circularA.getCircularB()); CircularB circularB = (CircularB) applicationContext.getBean("circularB"); System.out.println(circularB.getCircularA()); }
結果輸出
上述示例是我們編碼中很常見的一種編碼方式
迴圈依賴詳解
瞭解迴圈依賴,得先了解bean的例項化過程,bean的例項化請看作者寫的spring原始碼解析之bean的例項化
迴圈依賴流程
總結
A B迴圈依賴,優先例項化完成的是B,再是A,因為A在DI的時候需要B的例項,B沒有例項化就需要例項化,但是B在例項化的時候,DI的時候需要A,此時的A已經提前暴露,放在三級快取中,所以我們能夠拿到A的例項,然後注入到B中,B例項化完成以後,返回B的例項,然後A完成DI後,A就完成了例項化。
幾點思考
多例為什麼不能迴圈依賴?
因為多例情況下,A在例項化的時候,在依賴注入B的時候,B的例項有多個,依賴哪一個?
所以多例情況下,是不能迴圈依賴的
spring在原始碼中也做了處理,在快取中拿不到例項後,else首先就判斷了多例,多例的迴圈依賴直接會報錯
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
通過構造器注入的方式,能迴圈依賴嗎?
看例子
CircularC 類
@Component
public class CircularC {
private CircularD circularD;
@Autowired
public CircularC(CircularD circularD) {
this.circularD = circularD;
}
}
CircularD 類
@Component
public class CircularD {
private CircularC circularC;
@Autowired
public CircularD(CircularC circularC) {
this.circularC = circularC;
}
}
執行結果
程式拋了異常
why?
C在例項化的時候,因為構造器的引數是引用型別,會觸發beanFactory.getBean的操作,觸發D類的例項化,此時D例項化,D例項化的時候同理會觸發C的例項化,此時三個快取中是沒有任何的C的資訊,因為三級快取的暴露是在構造器例項化完成之後,所以在快取中拿不到C,會繼續走例項化流程,但是此時singletonsCurrentlyInCreation已經有了C,因為C在第一次例項化的時候,將beanName加入到了該容器中,此時就會丟擲異常,原始碼如下:
protected void beforeSingletonCreation(String beanName) {
//把beanName新增到singletonsCurrentlyInCreation Set容器中,在這個集合裡面的bean都是正在例項化的bean
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
所以構造器的方式的依賴注入是不能迴圈依賴的