Spring原理(二)--循环依赖原理

此篇文章建立在已经了解bean创建原理之上,若不了解,请先阅读本人上一篇文章
Spring原理(一)–IOC原理

1 场景

@Component
public class X {
    @Autowired
    Y y;
    public X(){
        System.out.println("X");
    }
}
@Component
public class Y {
    @Autowired
    X x;
    public Y(){
        System.out.println("Y");
    }
}

2 原理

1 前提知识

在上一篇文章中,我们知道bean在实例化后,会把自己放入三级缓存,并会把自己放入创建队列中,循环依赖就是基于三级缓存实现的。
在这里插入图片描述在这里插入图片描述

2 大体过程

Spring解决循环依赖的诀窍就在于singletonFactories这个三级缓存,X首先完成实例化(调用了构造器),并且将自己提前曝光到singletonFactories中(如果支持循环依赖(spring默认开启,变量值为true表示),会将ObjectFactory对象工厂put进singletonFactories中),此时进行填充属性,发现自己依赖对象Y,此时就尝试去get(Y),发现Y还没有被实例化,所以走实例化流程,实例化后Y在填充属性的时候发现自己依赖了对象X,于是尝试get(X),尝试一级缓存singletonObjects(肯定没有,因为X还没初始化完全),尝试二级缓存earlySingletonObjects(条件是一级缓存中拿不到并且对象正在创建中(正在创建的对象会被放在一个set集合中),也没有),尝试三级缓存singletonFactories(拿到后将其放入到二级缓存,然后将尝试三级缓存singletonFactories内的对象remove掉),由于A通过ObjectFactory将自己提前曝光了,所以Y能够通ObjectFactory.getObject拿到X对象(并且可以通过工厂提前实现aop),Y完全初始化之后将自己放入到一级缓存singletonObjects中,X此时能拿到Y的对象最终X也完成了初始化,进去了一级缓存singletonObjects中。

3 代码验证

根据上一篇文章,如图循环依赖就是在populateBean(beanName, mbd, instanceWrapper)中进行的
其核心代码是

PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

当进行x的属性注入时,发现需要注入y,就会去单例池拿y,上面方法最终会执行到
beanFactory.getBean(beanName),根据上篇文章,getBean最终会调用getSingleton

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//先从单例池中拿y,因为此时y还没完成创建,是拿不到的
		Object singletonObject = this.singletonObjects.get(beanName);
		//isSingletonCurrentlyInCreation判断y是否正在被创建,此时y没有被创建,返回false
		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;
	}

上一步返回false,就会进行y的创建,和x一样最终也会走到属性注入,这时就去就会去单例池拿x,还是会走到上述代码

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	 //因为此时x还没有被创建成功,在单例池中依然拿不到
		Object singletonObject = this.singletonObjects.get(beanName);
		//此时因为x已加入创建队列,所以isSingletonCurrentlyInCreation(beanName)返回true
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
			 //从二级缓存中拿x,拿不到(使用二级缓存的原因是,防止多个循环依赖的情况下,三级缓存重复生产对象,因为三级缓存是一个对象工厂,生产对象会费时)
				singletonObject = this.earlySingletonObjects.get(beanName);
				//allowEarlyReference代表是否支持循环依赖,默认为true
				if (singletonObject == null && allowEarlyReference) {
				 //此时就回去三级缓存拿x,此时x在实例化时是放在三级缓存中的
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
					  
						singletonObject = singletonFactory.getObject();
						//将x放入二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						//从三级缓存移除二级缓存
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

所以y在进行属性注入时,能在三级缓存中拿到x,完成注入,从而y完成创建,将自己放入一级缓存singletonObjects中。然后x就能拿到y,完成创建
注:
构造器方式无法解决循环依赖是因为三级缓存的前提是完成实例化执行了构造器,所以构造器的循环依赖没法解决

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值