(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的流程图如下:
在这里插入图片描述

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