循环依赖的源码解析

循环依赖的概念

A对象的创建,需要B对象;B对象的创建需要A对象,此时便出现循环依赖问题,A和B都无法创建成功。

循环依赖的案例

@Service
public class ServiceA {
 
    @Autowired
    private ServiceB serviceB;
}
 
@Service
public class ServiceB {
 
    @Autowired
    private ServiceA serviceA;
}

三级缓存

  1. 为了解决循环依赖,用到了3个缓存。
  2. singletonObjects:单例池,一级缓存。
  3. earlySingletonObjects:未完成初始化的单例池,也称之为二级缓存 。
  4. singletonFactories:三级缓存,存放的是创建对象的lambda表达式。如果是普通对象直接返回,如果需要AOP则创建代理对象。

循环依赖的源码解析

当你看到 Spring 中提供了 get/set 或者注解,这样之所以能解决,首先是进行了一定的解耦。让类的创建和属性的填充分离,先创建出半成品Bean,再处理属性的填充,完成成品Bean的提供

创建A对象

  1. 尝试获取A对象,获取bean的入口,AbstractBeanFactory#doGetBean。从单例池中获取对象,DefaultSingletonBeanRegistry#getSingleton(String beanName, boolean allowEarlyReference)
@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
        //如果单例池中没有对象且该对象当前正在创建中
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            //获取早期创建
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}
  1. 创建Bean。如果是单例bean,则调用DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory) ,用传入的lambda表达式来创建对象。
if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

创建bean对象,AbstractAutowireCapableBeanFactory#createBean()。在走到真正的创建对象之前会将三级缓存设置。

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
  1. 设置A对象中的属性B,AbstractAutowireCapableBeanFactory#populateBean

设置B属性

  1. 尝试获取B对象
  2. 创建B原始对象
  3. 设置B对象中的属性A

设置A属性

  1. 尝试获取A对象。单例池中不存在,且对象正在创建中,则获取earlySingletonObjectearlySingletonObject不存在,调用三级缓存的对象工厂生成。AbstractAutowireCapableBeanFactory#getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

后续操作

  1. 给B对象设置A属性,A属性是earlySingletonObject
  2. B对象的A属性设置完成,创建成功。
  3. A对象的B属性设置完成,创建成功。

Spring解决不了的循环依赖

使用构造器注入

@Component
public class ABean {

    private BBean bBean;

    public ABean(BBean bBean) {
        this.bBean = bBean;
        System.out.println("init");
    }
}

@Component
public class BBean {

    @Autowired
    private ABean aBean;

    public BBean(ABean aBean) {
        this.aBean = aBean;
    }

}
  1. 创建A对象的时候,需要用到B属性。AbstractAutowireCapableBeanFactory#doCreateBean->AbstractAutowireCapableBeanFactory#createBeanInstance
// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

找到构造器需要的B对象,进行生成。当B对象生成需要设置属性A的时候,再次获取A对象的时候,由于三级缓存中没有A对象的bean创建工厂,无法创建earlySingletonObject

循环依赖且用@Async注解修饰方法

@Service
public class A {

    @Autowired
    B b;

    @Async
    public void method() {
        b.xx();
    }
}

@Service
public class B {
    @Autowired
    A a;
}
  1. A对象创建完,初始化bean信息,执行AbstractAutowireCapableBeanFactory#initializeBean(),会根据@Async生成代理对象。AsyncAnnotationBeanPostProcessorBeanPostProcessor,不会在生成早期对象的时候进行代理。
  2. bean是初始化的bean,exposedObject是经过AsyncAnnotationBeanPostProcessor后置处理器处理过的。所以exposedObject和bean不相等。这时候B对象设置的是A的earlySingletonReference,是原始对象。而准备生成的实例却是代理对象。
  3. 如果是@Transactional,不是@Async,不会报错。原因是exposedObject == bean,都是原始对象。带有Transactional的对象在生成早期对象的时候,会执行AbstractAdvisorAutoProxyCreator#findCandidateAdvisors,会获取到BeanFactoryTransactionAttributeSourceAdvisor。代理对象应该是暴露出去的对象,所以进行赋值。
  4. bean初始化完成之后,后面还有一步去检查:第二级缓存是否存在, 暴露对象和原始对象是否相等。发现第二级缓存存在并且暴露对象和原始对象是不相等,会抛出异常。如果暴露对象和原始对象相等(初始化的时候没有改变对象),将earlySingletonReference赋值给暴露对象(如果有@Transactional或者@Aspect拦截,该早期对象是代理对象)。
//AbstractAutowireCapableBeanFactory#doCreateBean
		if (earlySingletonExposure) {
            //获取earlySingletonReference,如果没有,不创建
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}