Spring中如何解决循环依赖,singletonObjects,singletonFactories,earlySingletonObjects,一级缓存,二级缓存,三级缓存

所谓循环依赖是指, 两个或者多个Bean相互之间持有对方引用,比如BeanA引用了BeanB,BeanBU引用了BeanC,BeanC引用BeanA这种。
在Spring中只能解决通过setter方式且引用的Bean的作用域是Singleton级别
Spring中通过set方式注入形成的循环依赖是先将提前暴露刚实例化但是未进行其他任何处理的Bean的实例引用,这样返回了Bean实例的引用,后期对bean的任何处理,不会改变bean的引用地址。
实际实现上提前暴露一个单例工厂方法,返回了一个在创建中的Bean,这样其他Bean就能够获得他的引用。
我们假设两个Bean A B,相互setter依赖,A中有B的属性,B中有A的属性

假设是首先实例化A

在spring容器启动的最后阶段是需要实例化,其最后会通过遍历beanNames来进行bean的实例化,通过getBean方法来进行bean的实例化工作,而getBean方法的最终执行是在:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		// 这个时候获取循环依赖的单例,某个单例可能这时候实例化结束开始填充属性,需要获取相关属性,
		// 比如A依赖B,B也依赖A,A实例化之后需要填充属性,填充属性需要B的实例,但是B在实例化之后填充属性需要A,
		// 这时候在getSingleton的时候能够获取到A对应的实例的引用,即解决了循环依赖
		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 + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		// 缓存中没有,实例化bean
		else {
			...
				// Create bean instance.
				// 先判断bean是否是singleton,如果是通过ObjectFactory获取单例实例
				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;
						}
					});
					// 这里判断如果是FactoryBean,通过FactoryBean.getObject获取bean实例,
					// 如果不是FactoryBean,直接返回Bean本身
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
	...
	}

跟进getSingleton方法:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		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 + "'");
				}
				// 判断当前单例是否在创建,如果没有将beanName加入到singletonsCurrentlyInCreation
				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) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					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;
					}
					// 将beanName从移除singletonsCurrentlyInCreation
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					// 实现如下:
					// this.singletonObjects.put(beanName, singletonObject);
					// this.singletonFactories.remove(beanName);
					// this.earlySingletonObjects.remove(beanName);
					// this.registeredSingletons.add(beanName);
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

发现这里主要的工作是:

  1. 调用ObjectFactory.getObject之前将beanName加入到singletonsCurrentlyInCreation
  2. 调用ObjectFactory.getObject实例化单例
  3. 设置相关属性 singletonObjects singletonFactories earlySingletonObjects registeredSingletons

这里有几个比较重要的属性变量,需要着重说明一下:

  1. singletonObjects 单例对象列表, beanName -> bean实例 也就是我们常说的一级缓存
  2. singletonFactories 单例工厂列表 beanName -> beanFactory 常说的三级缓存
  3. earlySingletonObjects 循环对象依赖列表,对象在创建之后,进行注入过程中,发现产生了循环依赖,那么会将对象放入到这个队列,并且从singletonFactories中移除掉。 常说的二级队列
  4. singletonsCurrentlyInCreation 正在创建的单例名称队列
  5. registeredSingletons 已经创建成功的单例名称列表

singletonObjects 单例对象列表, beanName -> bean实例 也就是我们常说的一级缓存,这个里面保存的是一个已经完全实例化完整的bean,earlySingletonObjects 这是二级缓存,这个里面保存的是一个已经初始化,尚未实例化的对象,singletonFactories 三级缓存,这里面保存了一个对象生成的ObjectFactory方法,里面会调用createBean方法
当我们刚开始实例化A的时候,最终会调用工厂方法,继而调用createBean方法,

  1. 在createBean A之前 singletonsCurrentlyInCreation存在A
  2. 调用createBean后,初始化A之后,填充A的属性之前,调用:
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));
		}
		protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
				this.singletonFactories.put(beanName, singletonFactory);
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}
	// 如果SmartInstantiationAwareBeanPostProcessor返回A的实例,这时候返回的就是已经实例化的A
	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来说

singletonFactories 包含 A
registeredSingletons 包含A
singletonsCurrentlyInCreation 包含A
singletonObjects 不包含A
earlySingletonObjects 不包含A

接下来需要填充A的属性,调用populateBean,这时候B还未实例化,同样是调用getBean方法实例化B,
先初始化B,这个步骤与A上面描述的步骤一模一样,没有区别,但是接下里填充B的属性的时候就有区别了,这时候由于B中含有A的依赖,需要调用getBean -> doGetBean 来获取A的实例,

Object sharedInstance = getSingleton(beanName);
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		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 + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
		····
// 这时候B 获取A的实例
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		// 这时候singletonObjects没有A,但是isSingletonCurrentlyInCreation含有A
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
			// earlySingletonObjects中没有A
				singletonObject = this.earlySingletonObjects.get(beanName);
				// 满足条件
				if (singletonObject == null && allowEarlyReference) {
				   // singletonFactories包含A
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
					//获取到A实例的引用
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

这时候上面调用结束之后,之前5个属性中A的相关部分如下:

singletonFactories 不包含 A
registeredSingletons 包含A
singletonsCurrentlyInCreation 包含A
singletonObjects 不包含A
earlySingletonObjects 包含A

这样B中就获取到了A的实例的引用(这时A只是初始化,并没有完全的实例化,很多属性还未填充)
B顺利创建完成且设置了A的依赖,getSingleton中facttoryObject.getObject(实际上就是createBean方法)执行完成,执行后续方法,也就是设置5个属性中B的相关部分,设置完之后状态如下:

singletonFactories 不包含B
registeredSingletons 包含B
singletonsCurrentlyInCreation 不包含B
singletonObjects 包含B
earlySingletonObjects 不包含B

B实例化初始化完成之后,A拿到了B的引用,并初始化完成,也执行上面和B后续一样的流程,
,也就是设置5个属性中B的相关部分,设置完之后状态如下:

singletonFactories 不包含A
registeredSingletons 包含A
singletonsCurrentlyInCreation 不包含A
singletonObjects 包含A
earlySingletonObjects 包含A

这样完成了A、B之间相互依赖的注入。可以看到其主要是在A实例化之后但是未初始化之前暴露出A的引用,并通过下面这5个属性来控制:

  1. singletonObjects 单例对象列表, beanName -> bean实例
  2. singletonFactories 单例工厂列表 beanName -> ObjectFactory
  3. earlySingletonObjects 循环对象依赖列表,对象在创建之后,进行注入过程中,发现产生了循环依赖,那么会将对象放入到这个队列,并且从singletonFactories中移除掉。
  4. singletonsCurrentlyInCreation 正在创建的单例名称队列
  5. registeredSingletons 已经创建成功的单例名称列表

通过上面可以看到,spring利用了三级缓存来解决循环依赖:
singletonObjects 单例对象列表, beanName -> bean实例 也就是我们常说的一级缓存,这个里面保存的是一个已经完全实例化完整的bean,earlySingletonObjects 这是二级缓存,这个里面保存的是一个已经初始化,尚未实例化的对象,singletonFactories 三级缓存,这里面保存了一个对象生成的ObjectFactory方法,里面会调用createBean方法

当一个类进行实例化的时候,首先是通过ObjectFactorycreateBeran获取Bean:

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

然后判断isSingletonCurrentlyInCreation,如果是,那么会再次将已经初始化尚未实例化的Bean封装成一个ObjectFactory放入到三级缓存中去。这时候bean已经初始化尚未实例化,且只在三级缓存中。(同时A会加入到singletonsCurrentlyInCreation中)
然后进行Bean的实例化,开始填充属性,这时候发现依赖B,那么和A一样,也进行初始化,放入到三级缓存,然后发现依赖A,这时候A在三级缓存中,这时候将A从三级缓存的ObjectFactory抽取出来放入到二级缓存,同时移除三级缓存中ObjectFactory,这样一个已经初始化尚未实例化的A就出来了,A就可以赋值给B了。B进行剩余属性填充,完成实例化。
B完成实例化后,上面上面getSingleton执行最后会执行afterSingletonCreation(beanName);:

protected void afterSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
			throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
		}
	}

如果是新加入的单例,还会执行addSingleton:

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

这时候,B只有在singletonObjects和registeredSingletons中,二级缓存,三级缓存,singletonsCurrentlyInCreation都会移除B

然后A继续实例化,这时候B已经能够获取到一个完成的实例了。A实例化完之后,将会执行B一样的清除逻辑。

也就是说,在创建A的过程中,A会在三级缓存或二级缓存中,一定在singletonsCurrentlyInCreation,完成实例化之后都会清除,只会在singletonObjects中。
这样在Bean实例化的时候,如果发生了循环依赖,通过二级缓存(earlySingletonObjects)里面的半成品对象解决循环依赖问题

  • 8
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值