spring单例下循环依赖的处理,三级缓存

最近在看spring的源码,这里专门记录下spring对循环依赖的处理。

简单介绍什么是循环依赖:有两个类A\B,A实例化的时候需要B的bean,B实例化的时候也需要A的bean,AB之间就是循环依赖。spring中,在非单例下,spring是不允许存在循环依赖的;下面主要看下spring对循环依赖是怎么处理的。

Spring单例对象的初始化其实可以分为三步:

第一步:实例化,createBeanInstance, 实际上就是调用对应的构造方法构造对象,此时只是调用了构造方法,spring xml中指定的property并没有进行populate

第二步:填充属性,populateBean,这步对spring xml中指定的property进行populate

第三步:initializeBean,调用spring xml中指定的init方法,或者AfterPropertiesSet方法
会发生循环依赖的步骤集中在第一步和第二步。

下面直接进入创建过程,并在创建过程中附上相关源码:

A创建第一步实例化A,并且调用了如下两处代码:

			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	protected void beforeSingletonCreation(String beanName) {
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

上面第一段代码将A的ObjectFactory添加到singletonFactories中了,这里就是三级缓存,已经将未创建好的A显示出来了

第二段代码将A的bean name加入到了singletonsCurrentlyInCreation中;

A创建第二步,填充属性B的时候,发现B没有创建好,所以此时开始创建B

创建 B第一步,实例化,

第二步实例化属性A,此时会调用下面的代码:

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 此时A还没有在singletonObjects缓存中
		Object singletonObject = this.singletonObjects.get(beanName);
        // A创建第一步会使isSingletonCurrentlyInCreation返回true,对应上面调用的beforeSingletonCreation方法
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
                    // A创建第一步曝光引用在这里使用,对应上面addSingletonFactory方法的调用
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

这段代码执行后,属性A已经有了。

然后进入B的第三步,至此B创建完成,但是其属性A还是未创建完全

接着是A的第二步和第三步,A也创建完成。

这种解决相互引用的方式称为三级缓存的方式,即整个流程涉及到三个变量(都是Map):

singletonObjects:一级缓存,存储beanName(key)和bean实例(value)之间的关系,这里存储的bean实例是已经完全创建完成的bean实例

earlySingletonObjects:二级缓存,也是存储beanName和bean实例之间的关系,注意和singletonObjects的区别,这里存储的bean实例是没有创建完成的bean实例,即该bean还在创建过程中,为了解决循环引用的问题,将未创建完全的bean缓存起来。
singletonFactories:三级缓存,用于保存beanName和bean工厂之间的关系。当三级缓存创建bean成功后,会将bean放入二级缓存,并将beanName对应的beanFactory从singletonFactories中移除。

ObjectFactory:有getobject()方法,在创建单例bean的过程中,为了解决循环依赖问题,会创建beanName对应的ObjectFactory放入SingletonFactoies中,达到提前曝光bean的目的。三级缓存singletonFactory.getObject()(三级缓存)获取,如果获取到了则:
    this.earlySingletonObjects.put(beanName, singletonObject);
    this.singletonFactories.remove(beanName);
为什么是三级缓存?getEarlyBeanReference中支持AwareBeanPostProcessor这样的后置处理器,给用户提供接口扩展的。

参考 https://segmentfault.com/q/1010000019485013?sort=created

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值