(Spring源碼分析)Spring解決循環依賴源碼分析

一、什麼是循環依賴

Spring中的bean存在循環嵌套依賴的情況就叫做循環依賴

如下圖:

  • 情況一:A依賴着B,B也依賴着A,這是循環依賴
    在這裏插入圖片描述
  • 情況二:A依賴着B,B也依賴着C,C依賴着A,這是循環依賴
    在這裏插入圖片描述

二、循環依賴的Demo

@Component
public class A {
  @Autowired
  private B b;
  
  ......
}

@Component
public class B {
  @Autowired
  private A a;
  
  ......
}

三、Spring解決循環依賴的源碼分析

Spring循環依賴出現在創建bean時,首先調用AbstractBeanFactory#getBean()方法獲取bean

getBean(beanName)

@Override
public Object getBean(String name) throws BeansException {
  return doGetBean(name, null, null, false);
}

doGetBean(name, null, null, false)

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
  // 根據beanName嘗試從三級緩存中獲取bean實例
  Object sharedInstance = getSingleton(beanName);

  // 當三級緩存中存在此bean,表示當前該bean已創建完成 || 正在創建
  if (sharedInstance != null && args == null) {
    // 返回對應的實例,有時候存在諸如BeanFactory的情況並不是直接返回實例本身而是返回指定方法返回的實例
    // 如果sharedInstance是普通的單例bean,下面的方法會直接返回,但如果sharedInstance是FactoryBean類型的,
    // 則需要調用getObject工廠方法獲取bean實例,如果用戶想獲取FactoryBean本身,這裏也不會做特別的處理
    bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  }

  // 當bean還未創建
  else {
    // 這一大段代碼省略
    ......

    // 正式開始創建bean實例
    if (mbd.isSingleton()) { // 當該bean的scope爲singleton或者爲空時
      sharedInstance = getSingleton(beanName, () -> { // 從三級緩存中獲取bean實例
        try {
          return createBean(beanName, mbd, args); // 真正創建bean
        }
        catch (BeansException ex) {
        }
      });
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
  }

  // 創建bean的後續處理
  ......

  return (T) bean;
}

getSingleton(beanName)

/**
 * 嘗試從三級緩存中獲取bean實例
 * 
 * 從一級緩存(單例池) -> 二級緩存 -> 三級緩存依次獲取,當三級緩存中都不存在bean實例時,那個該bean處於還未創建的狀態
 *
 * 這裏解釋一下三級緩存分別的作用
 */
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  // 嘗試從三級緩存中獲取bean實例
  Object singletonObject = this.singletonObjects.get(beanName); // 從一級緩存中獲取bean

  // 如果一級緩存中不存在該bean實例  && 該bean正在創建中
  if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // isSingletonCurrentlyInCreation(beanName)判斷這個bean是否在創建過程中,對象是否有循環依賴
    synchronized (this.singletonObjects) {
      singletonObject = this.earlySingletonObjects.get(beanName); // 嘗試從二級緩存中獲取提前曝光的bean實例

      // 如果二級緩存中不存在giantbean實例 && 允許從singletonFactories從獲取bean實例
      if (singletonObject == null && allowEarlyReference) {
        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); // 從三級緩存中獲取bean實例

        // 如果bean存在,將該bean實例從三級緩存升級到二級緩存中提前曝光bean實例,並且從三級緩存中刪除
        if (singletonFactory != null) {
          singletonObject = singletonFactory.getObject();
          this.earlySingletonObjects.put(beanName, singletonObject);
          this.singletonFactories.remove(beanName);
        }
      }
    }
  }
  return singletonObject;
}

createBean(beanName, mbd, args)

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
	// 這一大段代碼省略
  ......
  
  // 實例化bean
  Object beanInstance = doCreateBean(beanName, mbdToUse, args);

  return beanInstance;
}

doCreateBean(beanName, mbdToUse, args)

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
	// 這一大段代碼省略
  ......

  // 創建bean實例轉化成BeanWrapper對象
  if (instanceWrapper == null) {
    // 調用bean的構造方法進行初始化,經過這一步,bean屬性並沒有被賦值,只是一個空殼,這是bean初始化的【早期對象】
    instanceWrapper = createBeanInstance(beanName, mbd, args);
  }
  
  ......

  // 判斷bean是否存在循環依賴
  // 如果當前bean是單例,且支持循環依賴,且當前bean正在創建,通過往singletonFactories添加一個objectFactory,這樣後期如果有其他bean依賴該bean 可以從singletonFactories獲取到bean
  boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                    isSingletonCurrentlyInCreation(beanName));
  if (earlySingletonExposure) {
    // 添加工廠對象到singletonFactories緩存中,【提前暴露早期對象】
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
  }

  // 給已經已經初始化的屬性賦值,包括完成bean的依賴注入
  populateBean(beanName, mbd, instanceWrapper);

  ......

  return exposedObject;
}
populateBean(beanName, mbd, instanceWrapper)
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	// 這一大段代碼省略
	......

  // 爲屬性賦值
	applyPropertyValues(beanName, mbd, bw, pvs);
}
applyPropertyValues(beanName, mbd, bw, pvs)
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {

    // 這一大段代碼省略
    ......

	// 爲當前bean中屬性賦值,包括依賴注入的屬性
	Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
	
	// 這一大段代碼省略
    ......
}
valueResolver.resolveValueIfNecessary(pv, originalValue)
/**
 * 如果當前初始化的bean有屬性需要注入的,將會調用resolveReference(argName, ref)來返回需要注入的bean
 */
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
	// 獲取需要依賴注入屬性的值
	if (value instanceof RuntimeBeanReference) {
		RuntimeBeanReference ref = (RuntimeBeanReference) value;
		return resolveReference(argName, ref);
	}
	
	// 這一大段代碼省略
    ......
}
resolveReference(argName, ref)
/**
 * 在該方法中,會爲當前初始化bean主要爲屬性注入另外一個bean,調用getBean()方法獲取需要注入的bean,最終注入到屬性中
 */
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
	try {
		Object bean;
		String refName = ref.getBeanName();
		refName = String.valueOf(doEvaluate(refName));
		if (ref.isToParent()) {
			if (this.beanFactory.getParentBeanFactory() == null) {
				throw new BeanCreationException(
						this.beanDefinition.getResourceDescription(), this.beanName,
						"Can't resolve reference to bean '" + refName +
								"' in parent factory: no parent factory available");
			}
			bean = this.beanFactory.getParentBeanFactory().getBean(refName);
		}
		else {
		    // 當前初始化bean主要爲屬性注入另外一個bean,調用getBean()方法獲取需要注入的bean,最終注入到屬性中
			bean = this.beanFactory.getBean(refName);
			this.beanFactory.registerDependentBean(refName, this.beanName);
		}
		if (bean instanceof NullBean) {
			bean = null;
		}
		return bean;
	}
	catch (BeansException ex) {
		throw new BeanCreationException(
				this.beanDefinition.getResourceDescription(), this.beanName,
				"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
	}
}

調用getBean()方法又回到了開頭的getBean(beanName),此時去實例化B,實例化B的時候一步執行剛纔實例bean A的步驟,然後到了調用populateBean(beanName, mbd, instanceWrapper)方法注入bean A,又回到第二次實例化bean A,在調用getSingleton(beanName)方法嘗試從三級緩存中獲取bean實例時,從第三級緩存singletonFactories中獲取到正在創建的bean A,這樣就獲取到bean A了,然後返回給bean B注入到bean B的屬性中,完成bean B的初始化了,最後返回給bean A注入到bean A的屬性中,這樣就完成了循環依賴了。初始化bean A和bean B的流程圖如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章