Spring解决循环依赖的思路
一. 什么是循环依赖
循环依赖也就是循环引用,指两个或多个对象互相持有对方的引用。通俗地说,假设在Spring中有3个Service Bean,分别为ServiceA、ServiceB和ServiceC,如果ServiceA引用了ServiceB,ServiceB引用了ServiceC,而ServiceC又引用了ServiceA,最终形成可一个环,这样就出现了循环依赖。
二. Spring如何解决循环依赖
对Spring来说循环依赖,有以下几种:
- Prototype类型Bean的循环依赖
- 构造器循环依赖
- setter循环依赖
对于第1类和第2类的循环依赖,Spring的处理是不解决,直接抛出BeanCurrentlyInCreationException异常。
因此,Spring只处理Singleton类型的Bean的setter循环依赖 。其处理思路大概为:对于循环依赖的Bean,提前暴露一个单例工厂ObjectFactory,从而使得其他Bean能引用到该Bean。以前面所说的三个Service为例,具体步骤如下:
- Spring 容器创建单例ServiceA,首先根据无参构造器创建Bean,并提前暴露一个 “ObjectFactory”,表示一个创建中的Bean,并将ServiceA放到“当前正在创建的Bean池”中,然后进行 setter注入ServiceB。
- ServiceB通过同样的方式,暴露一个ObjectFactory,并将ServiceB放入“当前正在创建的Bean池”中,然后进行setter注入ServiceC。
- ServiceC也通过同样的方式,暴露ObjectFactory并将Bean入池,接下来在注入ServiceA的时候,发现ServiceA处于位于正在创建池中,说明出现了循环依赖,此时由于ServiceA已经提前暴露了一个ObjectFactory,则ServiceC会注入ServiceA工厂返回的正在创建中的对象。
- 最后通过setter注入ServiceB和ServiceA,完成依赖创建过程。
三. 源码分析
说了这么多理论,下面来分析下源码。我们使用Spring时的一个基本操作就是Bean的获取,那么我们从AbstractBeanFactory的getBean()方法入手:
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
getBean()只是一个接口方法,核心逻辑在doGetBean()中:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//解析beanName
final String beanName = transformedBeanName(name);
Object bean;
//直接从缓存中或者singletonFactories中对应的ObjectFactory获取
//检查缓存中或者实例工厂中是否有对应的实例,这样处理是为了解决单例Bean循环依赖的问题
//在创建单例Bean的过程中会存在依赖注入的情况,而在依赖注入过程中,为了避免循环依赖,Spring的处理是:
//不等Bean创建完成,就提前曝光创建Bean的ObjectFactory,也就是将ObjectFactory加入到缓存中,
//一旦一个Bean创建时需要依赖上一个Bean,则直接从缓存中获取ObjectFactory
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//返回对应的实例,因为从缓存中获取的Object未必是Bean本身,可能是FactoryBean之类的,需要调用这个方法获取真正的Bean
//有时会返回Bean指定方法所创建的对象而不是Bean本身,如FactoryBean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//Spring只处理Singleton类型Bean的循环依赖
//对于Prototype类型如果存在循环依赖,直接抛出BeanCurrentlyInCreationException
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//如果当前容器的BeanDefinition列表不存在Bean的定义,且父容器不为空,则尝试从parentBeanFactory中加载Bean
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
//如果不仅仅是做类型检查,则是要创建Bean,则先将Bean标记为已创建状态
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
//获取Bean的定义——RootBeanDefinition
//如果指定的Bean是子Bean的话,则同时会合并父Bean的属性
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//如果存在依赖的Bean,则递归实例化所有依赖的Bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//缓存依赖调用
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
//所有依赖Bean已经实例化完成,开始实例化自身
//SingletonBean的创建
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);
}
//Prototype的创建
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//其他Scope类型Bean的创建
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
//类型检查:如果传入的requiredType不为空,则对创建好的Bean进行类型校验,如果不满足类型则抛出BeanNotOfRequiredTypeException
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
代码的核心部分我已经加了注释。在获取Bean时,首先会调用getSingleton()方法,因为Spring会将所有Singleton类型的Bean缓存起来,因此首先尝试从缓存中获取。而循环依赖的处理也在这个方法中。点进去看一下:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//首先从singletonObject缓存中获取,如果存在直接返回
Object singletonObject = this.singletonObjects.get(beanName);
//如果缓存中不存在,则检查singletonsCurrentlyInCreation,是否该beanName正在创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//如果singletonsCurrentlyInCreation中存在beanName,说明该Bean正在创建
//即出现了循环依赖的情况
synchronized (this.singletonObjects) {
//尝试从earlySingletonObjects中获取Bean
singletonObject = this.earlySingletonObjects.get(beanName);
//如果earlySingletonObjects中也不存在,且允许提前暴露Bean,则从singletonFactories中获取Bean对应的ObjectFactory
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
//如果Bean对应的ObjectFactory存在,则使用ObjectFactory创建Bean,将Bean加入到earlySingletonObjects中
//并且从singletonFactories中移除该singletonFactory
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
刚方法主要做了以下处理:
- 首先尝试从singletonObjects缓存中获取Bean,如果获取到了,说明Bean已经创建完成,直接返回即可。
- 缓存中不存在,则检查是否该Bean正在创建,这是解决循环依赖的关键。Spring通过singletonsCurrentlyInCreation这个Set保存了所有正在创建中的beanName。如果在创建一个Bean时,在singletonsCurrentlyInCreation找到了这个Bean的name,则说明出现了循环依赖。
- 首先尝试从earlySingletonObjects中获取暴露的创建中的对象,如果不存在,再尝试从singletonFactories中获取提前暴露的对象工程BeanFactory,并调用其getObject()方法,实例化一个提前暴露的正在创建中的对象并放入earlySingletonObjects,然后返回这个创建中的对象。
可以看到,Spring解决循环依赖的方式就是"提前暴露法",在循环引用时,引用提前暴露的正在创建中的对象而非真正实例化完成的对象。
那么singletonFactory中的BeanFactory是在何时创建的呢?搜索调用链,可以看到在AbstractAutowireCapableBeanFactory的doCreateBean()方法中:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
//实例化Bean,大部分情况都是调用其无参构造器
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
//允许MergedBeanDefinitionPostProcessor修改BeanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//将刚刚实例化完成的Bean,以ObjectFactory的形式放入singletonFactories中,以解决循环依赖的问题
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));
}
...
}
可以看到,在创建Bean的过程中,一旦实例化完成,就将Bean以ObjectFactory的形式放入singletonFactories中,以解决循环依赖的问题。此时的Bean还未进行属性的赋值和依赖的注入,就是一个空壳。
而在Bean创建完成后,会将其对应的ObjectFactory移除,代码如下:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
四. 总结
至此,Spring的循环依赖解决思路基本描述完成。可以看到,整体的处理方式还是很巧妙的。主要流程总结如下:
- 创建Bean过程中,将beanName放入singletonsCurrentlyInCreation正在创建池中,并创建对应的ObjectFactory放入对象工厂缓存池。
- 解析Bean依赖过程中,如果发现存在了循环依赖,则直接引用ObjectFactory所创建的提前暴露的Bean。
- Bean的创建结束后,将其从singletonsCurrentlyInCreation中移除,并删除对应的ObjectFactory。
整个过程中,Spring对缓存的处理也很巧妙,现将常用的缓存总结如下(DefaultSingletonBeanRegistry类中):
/**
* 用于保存所有已创建的Singleton Bean
* key:beanName
* value:Singleton Bean
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
* 用于保存创建Bean对应的ObjectFactory工厂
* key:beanName
* value:Bean对应的ObjectFactory
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/**
* 用于保存提前暴露出的Bean,与singletonObjects不同的是,这里的Bean可能还未创建完成,但是通过getBean()也能够获取到,主要是为了解决循环依赖的问题
* 当Bean创建完成后,会从该缓存中移除
* key:beanName
* value:提前暴露出的Bean
*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/**
* 用于保存所有已经注册号的beanName
*/
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);