Spring自問自答系列3----循環依賴

個人直覺告訴我循環依賴一定會致使死鎖。 可是Spring支持循環依賴,因此本文就來探討Spring底層是如何實現循環依賴的。java

Spring中循環依賴代碼的書寫

本文Spring的依賴注入經過註解形式實現 A.java緩存

class A {
    @Autowired
    private B b;
}

B.javapost

class B {
    @Autowired
    private A a;
}

第一眼會感受這依賴不是無限循環下去了嗎? 可是想一想的確是可行的。this

Spring循環依賴的實現

首先須要瞭解SpringBeanFactory中的一些容器:code

緩存 用途
singletonObjects 用於存放徹底初始化好的 bean,從該緩存中取出的 bean 能夠直接使用
earlySingletonObjects 存放原始的 bean 對象(還沒有填充屬性),用於解決循環依賴
singletonFactories 存放 bean 工廠對象,用於解決循環依賴
singletonsCurrentlyInCreation 存放當前正在建立的bean

循環依賴流程以下:對象

  1. getBean("a")
  2. 調用第二個getSingleton方法
  3. 發如今singletonFactory裏沒有A實例,開始實例化A
  4. 執行InstantiationAwareBeanPostProcessor.postProcessPropertyValues注入參數,發現須要B
  5. getBean("b")
  6. 實例化B
  7. 執行InstantiationAwareBeanPostProcessor.postProcessPropertyValues注入參數,發現須要A
  8. getBean("a")
  9. 調用第一個getSingleton方法獲取A實例,注入進B實例中的A參數
  10. B實例初始化成功
  11. A實例注入B參數
  12. A實例初始化成功

關鍵代碼

DefaultSingletonBeanRegistry.java中getSingleton(String beanName, boolean allowEarlyReference)方法:rem

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		
		// 判斷bean是否正在建立過程當中 
		// 好比A正在初始化過程當中須要依賴注入B參數
		// Spring就須要區建立B實例,這時候A就在初始化過程當中
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
					    
					    // earlySingletonObject用來解決循環依賴
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
相關文章
相關標籤/搜索