Spring循环依赖问题

什么是循环依赖问题?

有A、B两个类,A类持有B属性,B类持有A属性。当初始化A对象的时候需要给A的B属性赋值,此时会初始化B对象,但初始化B对象需要给B的A属性赋值,但此时A还没初始化成功,导致最后A和B都无法初始化。

如何解决循环依赖问题?

针对于上述场景,解决循环依赖问题很简单,把初始化分成两步,第一步创建属性值为空的对象,第二步再给对象赋值。对应的就是使用二级缓存,缓存1存放A、B的空对象(属性值都为null),缓存2存放A、B的初始化完成的对象,缓存1存放的半成品对象因为已经生成实例了,所以可以拿来赋值。

Spring如何解决循环依赖问题?

Spring在二级缓存的基础上,增加了第三级缓存,来解决循环依赖问题。

Spring为什么不使用二级缓存,而使用三级缓存?

因为对于Spring而言,二级缓存不能够满足需要。

在Spring的Bean创建过程中,每个Bean都有其固定的创建流程(即生命周期),这里从网上找了一张图。

Spring循环依赖问题_第1张图片

从上图可以看出,针对于普通的对象,我们的循环依赖问题应该是在步骤2进行解决的。

但针对于需要进行AOP处理的对象,Spring是在步骤7的时候才会去创建代理对象,循环依赖问题已经在步骤2发生了,根本还没有走到步骤7。此时为了解决AOP的循环依赖问题,又不破坏Spring原有的创建Bean的生命周期,引入了第三级缓存。

第三级缓存存放创建Bean对象的函数式接口,该函数式接口可以让Bean的代理对象在任意需要时创建,但仅是应用在循环依赖场景发生之时才会用到第三级缓存。可以算作是Spring的一种特殊处理吧。

源码的具体位置

从下面可以看出,只有循环依赖的时候isSingletonCurrentlyInCreation(beanName)值才会是true,表示需要的实例正在创建过程中,然后使用三级缓存通过getEarlyBeanReference方法生成对象(如果有代理则是代理对象)

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果需要注入的值正在被创建(循环依赖时才会进入这个方法),那么使用三级缓存的构造函数创建,
		//创建完成后放在二级缓存当中,再把三级缓存的值移除
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				//通过allowEarlyReference控制,是否需要在这个时候创建代理对象
				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 != NULL_OBJECT ? singletonObject : null);
	}

Spring循环依赖问题_第2张图片

从下图可以看出,会调用AbstractAutoProxyCreator类的getEarlyBeanReference方法进行实例创建。

Spring循环依赖问题_第3张图片

 

你可能感兴趣的:(Springboot源码系列,缓存,java,spring)