ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2020-11-28 19:01:05  阅读:210  来源: 互联网

标签:缓存 singletonFactories get -- Spring beanName singletonObjects singletonObject 原理


此篇文章建立在已经了解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,完成创建
注:
构造器方式无法解决循环依赖是因为三级缓存的前提是完成实例化执行了构造器,所以构造器的循环依赖没法解决

标签:缓存,singletonFactories,get,--,Spring,beanName,singletonObjects,singletonObject,原理
来源: https://blog.csdn.net/weixin_45876565/article/details/110288933

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有