天天看點

(Spring源碼分析)Spring解決循環依賴源碼分析一、什麼是循環依賴二、循環依賴的Demo三、Spring解決循環依賴的源碼分析

目錄

  • 一、什麼是循環依賴
  • 二、循環依賴的Demo
  • 三、Spring解決循環依賴的源碼分析
    • getBean(beanName)
    • doGetBean(name, null, null, false)
      • getSingleton(beanName)
      • createBean(beanName, mbd, args)
        • doCreateBean(beanName, mbdToUse, args)
          • populateBean(beanName, mbd, instanceWrapper)
          • applyPropertyValues(beanName, mbd, bw, pvs)
          • valueResolver.resolveValueIfNecessary(pv, originalValue)
            • resolveReference(argName, ref)

一、什麼是循環依賴

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

如下圖:

  • 情況一:A依賴着B,B也依賴着A,這是循環依賴
    (Spring源碼分析)Spring解決循環依賴源碼分析一、什麼是循環依賴二、循環依賴的Demo三、Spring解決循環依賴的源碼分析
  • 情況二:A依賴着B,B也依賴着C,C依賴着A,這是循環依賴
    (Spring源碼分析)Spring解決循環依賴源碼分析一、什麼是循環依賴二、循環依賴的Demo三、Spring解決循環依賴的源碼分析

二、循環依賴的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的流程圖如下:

(Spring源碼分析)Spring解決循環依賴源碼分析一、什麼是循環依賴二、循環依賴的Demo三、Spring解決循環依賴的源碼分析

繼續閱讀