spring循环依赖通过三级缓存解决过程分析-其一

1.背景知识

我用的sprin-boot 2.7版本,这个版本(没查是哪个版本开始的)默认情况下是不会解决循环依赖,而是启动程序会报错,如果需要spring帮我们解决循环依赖,需要加上一个配置spring.main.allow-circular-references=true。spring现在建议通过构造方法注入,这个时候你就不要想解决循环依赖,解决不了,这样的目的就是希望我们自己把循环依赖解决好,如果真出现了循环依赖,要先考虑自己的程序设计是不是又有问题,随着微服务的的普及,基本上是不会出现循环依赖的问题了,如果出现了你得考虑自己打程序的业务、架构是不是有问题。实际上这个循环依赖不是很重要的东西,仅作为了解就行了,分析一下spring的解决思路。
首先spring中没有什么三级缓存的概念,因为getSingleton的时候,查找顺序是:singletonObjects-》
earlySingletonObjects-》singletonFactories。
这三个map就是大家常说的三级缓存:

singletonObjects : 一级缓存 :保存可以使用的单例bean
earlySingletonObjects :二级缓存:保存被循环依赖的bean对象(也可能是bean的代理对象)
singletonFactories: 三级缓存:bean实例化生成对应的ObjectFactory

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within 
					// full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects
						.get(beanName);
						if (singletonObject == null) {
							ObjectFactory<?> singletonFactory = 
							this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, 
								singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

2.bean创建过程

大致上可以分为以下几个过程:假设现在正在创建的bean是A,beanName就叫a

1)createBeanInstance(beanName, mbd, args)
2)addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
3)populateBean(beanName, mbd, instanceWrapper);
4)exposedObject = initializeBean(beanName, exposedObject, mbd);
5)if (earlySingletonReference != null)
6)addSingleton(beanName, singletonObject);

1)通过反射调用构造方法,产生对象a,这个是a还是个半成品,没有完成依赖注入和初始化。

2)把a的引用加入singletonFactories(三级缓存),key就是a的beanName,value是一个lambda表达式,可以简单成new了一个ObjectFactory的匿名对象,实现了getObject()方法,实现逻辑就是这个getEarlyBeanReference(beanName, mbd, bean),这样调用ObjectFactory.getObject()内部就是执行getEarlyBeanReference(beanName, mbd, bean)

3)依赖注入,如果a依赖的其他bean,其他bean又会执行整个bean的创建过程,结果就是a依赖注入其他的bean完成以后,其他bean必须是已经放入到单例池了。

4)初始化,这个时候如果a对象需要产生代理对象,在applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);里面会循环所有的BeanPostProcessor并执行postProcessAfterInitialization方法,其中有生成代理的BeanPostProcessor,会检查是配置了aop信息。

5)检查这个a是否存在earlySingletonObjects(二级缓存),如果存在(说明这个bean产生了循环依赖),则用earlySingletonObjects中的代理对象替换当前的bean引用

6)把bean的引用存入singletonObjects(一级缓存),同时移除beanName在二级、三级的其他引用。

到此整个bean就算创建完成了,可以使用了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值