Spring解决循环依赖过程

依赖注入三种方式

  1. 构造器注入
  2. set方法注入
  3. 注解方式注入

循环依赖场景

我们知道spring是通过依赖注入(DI)来完成属性的填充,而循环依赖是指实例化两个bean互相依赖对方的情况,比如A依赖B,B又依赖了A的情况,如图
在这里插入图片描述
实例化A时候发现依赖B,从而转去实例化B,在实例化B过程中又发现依赖了A,转去实例化A,如果没有应对策略,spring实例化bean过程就会出现死循环,所以为了解决这个问题,spring是使用了三级缓存,分别为如下所示:
Map<String, Object> singletonObjects
Map<String, Object> earlySingletonObjects
Map<String, ObjectFactory<?>> singletonFactories

这三个Map都是DefaultSingletonBeanRegistry类定义的成员变量,一级缓存singletonObjects存储着所有单例且已经实例化和初始化的bean, 二级缓存存储的是半成品,spring称之为早期对象,三级缓存存储的是实例化工厂方法,负责生产早期对象。

过程分析

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean 为了便于理解,只列出主要代码

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		... 省略部分代码
		...
      // Create bean instance.
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
						destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
}

从创建bean开始,getSingleton(beanName)先尝试从缓存找,看看能不能找到

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

以上这段代码经常被反复调用,是为了看能否从缓存拿到,因为是第一次进来所以肯定还拿不到,也就是返回singletonObject为null;
然后就接着走到
if (mbd.isSingleton())这个分支,进入代码org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton中

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

创建bean之前,beforeSingletonCreation(beanName)将当前bean标志为正在创建中,即添加到集合singletonsCurrentlyInCreation中,
接着singletonObject = singletonFactory.getObject()方法;
这个getObject()方法回到类AbstractBeanFactory的lambda表达式位置,即

if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
				}

调用createBean(beanName, mbd, args);
接着进入真正实现方法的位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
看到
Object beanInstance = doCreateBean(beanName, mbdToUse, args); 进入此方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		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;
		}
		// 省略代码
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
	

if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
earlySingletonExposure为true,因为上面集合singletonsCurrentlyInCreation已经添加进去,此时三级缓存singletonFactories出场了,key为bean的名称,value为一个lambda表达式,用来生成bean的早期对象(也就是所谓的半成品)。

populateBean(beanName, mbd, instanceWrapper)这里
实现属性填充,完成依赖注入对象的赋值,最终又会回到开始的doGetBean方法,相当于这里是一个递归效果,也就是跟上面一样的流程一样,又走了一遍。

现在假如循环依赖是A依赖B,B又依赖A,那么当创建A发现依赖了B,就会转去创建B,就会再次回到populateBean这里,此时三级缓存中存储了A和B
Ok,接着完成B的属性填充(populateBean)发现依赖了A,所以会转去创建A,还是doGetBean方法,只是有点不太一样,还是这段代码:
Object sharedInstance = getSingleton(beanName);

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

1级缓存没有,找二级缓存还是没有,然后从三级缓存找,这时候A是可以找到的,就是上面的lambda表达式,singletonFactory.getObject();
也就是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;
	}

此时A被提前生成出来,只不过它还是个半成品(还未完成初始化), 最后将它放到二级缓存earlySingletonObjects中,同时将A从三级缓存中移除,因为B依赖的A有了,接着就可以继续完成后续的初始化工作,B初始化完成后,它就是一个完整的对象,跟着被写入到一级缓存singletonObjects
B完成了初始化后,通过反射赋值给A,接着继续完成A剩余的初始化工作,A完成后续初始化后再也不是半成品了,最后也放到了一级缓存中了。

放入一级缓存的逻辑在类org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton中,也就是回到开始beforeSingletonCreation这个方法中,看到最后finally处

finally {
	if (recordSuppressedExceptions) {
		this.suppressedExceptions = null;
		}
	   afterSingletonCreation(beanName);
	}
    if (newSingleton) {
	 addSingleton(beanName, singletonObject);
	}

删除singletonsCurrentlyInCreation集合,删除二级和三级缓存对应的beanName,写入一级缓存。

简单总结其实就是这样的:
实例化A->放入缓存singletonFactories->填充属性发现依赖B->转去实例化B->放入缓存singletonFactories->填充属性发现依赖A->转去实例化A
->从singletonFactories拿到A半成品->A放入earlySingletonObjects->删缓存singletonFactories的A->赋值给B的属性a,接着完成B的初始化
->B放入singletonObjects->删除缓存singletonFactories的B->赋值给A的属性b->接着继续完成初始化A->放到singletonObjects->删除earlySingletonObjects和singletonFactories中的A.

以上整个过程就是Spring解决循环依赖的处理过程。

疑问

为什么是三级缓存,如果只用一级缓存或者二级缓存行不行?

好,先说一级缓存,这个应该很好解释,肯定不行,为什么?因为如果你把一个半成品放到了缓存中,别的线程来拿,因为缓存中存在,那么就直接拿去用了,这样岂不是GG了。

再谈二级缓存,这里就不得不提AOP代理了,因为有时候我们需要的是代理对象,而不是对象本身,比如很常见的,我们执行某个方法之前先加入一些逻辑,这时候拿到的就一个代理类了,而通过三级缓存singletonFactories来生成早期对象时,有可能就是代理对象,它是通过BeanPostProcessor后处理器做到的,也就是这段代码:

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;
	}

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference

@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			this.earlyProxyReferences.add(cacheKey);
		}
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

wrapIfNecessary完成的工作就是Aop代理,具体实现逻辑大家可以进去看看就知道了。

也就是说二级缓存其实也没问题,只是要把代理对象提前创建出来了,意思就是所有bean创建过程中,不管你有没有循环依赖,如果有需要代理的都给你提前创建了,而不是先放到三级缓存中了,这就违背了spring设计的原则。
Spring 的设计原则是尽可能保证普通对象创建完成之后,再生成其 AOP 代理,也就是尽可能延迟代理对象的生成。

所以 Spring 选择了使用三级缓存,这样既维持了自己定下来的设计原则,又能够解决循环依赖所带来的问题,真是皆大欢喜啊。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值