Spring-Bean循环依赖

1. 介绍

1.1 什么是Bean循环依赖

两个或则两个以上的对象互相依赖对方,最终形成闭环 。例如 A 对象依赖 B 对象,B 对象也依赖 A 对象。

1.2 会有什么问题

对象的创建过程会产生死循环,类似如下

1.3 Spring是如何解决的

通过三级缓存提前暴露对象来解决。

  • 一级缓存存的是成品对象(实例化和初始化都完成了的),我们应用中使用的对象就是一级缓存;

  • 二级缓存中存的是半成品(实例化,但是还未初始化),用来解决对象创建过程中的循环依赖问题;

  • 三级缓存中存的是 ObjectFactory,解决代理对象(如aop)循环依赖问题;

1.3.1 为什么需要二级缓存

半成品对象是没法直接使用的(存在 NPE 问题),所以 Spring 需要保证在启动的过程中,所有中间产生的半成品对象最终都会变成成品对象。如果将半成品对象和成品对象都混在一级缓存中,那么为了区分他们,势必会增加一些而外的标记和逻辑处理,这就会导致对象的创建过程变得复杂化了将半成品对象与成品对象分开存放,两级缓存各司其职,能够简化对象的创建过程,更简单、直观。

1.3.2 为什么需要三级缓存

如果 Spring 不引入 AOP,那么两级缓存就够了。首先明确AOP的实现是通过 postBeanProcess后置处理器,在初始化之后做代理操作的。Spring对象的加载流程:实例化,设置属性初始化(构造方法初始化?),AOP增强。如果没有三级缓存,初始化获取到的依赖对象就是没有AOP增强的对象。缓存的意义在于Spring对象的加载分多个步骤进行。可以根据1.2的图思考。

2. 源码

以User依赖People为例:

public class User {
    @Autowired
    private People people;
}

2.1 什么时候对象进三级缓存

2.1.1 Bean加载时查询一级、二级、三级缓存

// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 检查一级缓存是否有完整对象
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            // 如果一级缓存没有,则判断当前对象是否正在创建中,很明显一开始加载的时候不是
			// ...
		}
		return singletonObject;
	}

2.1.2  单例模式创建对象

// org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		        // ...
				if (mbd.isSingleton()) {
                    // 单例模式创建对象
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						// ...
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

		// ...
		return (T) bean;
	}

2.1.3  获取单例对象

// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
                // 标记当前对象正在创建中
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
                    // 移除对象正在创建中的标记
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
                    // 移除二级、三级缓存对象信息,添加至一级缓存
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

2.1.4 真正创建对象的ObjectFactory

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// ...
		try {
			// 如果对象继承InstantiationAwareBeanPostProcessor,可直接返回代理对象
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		// ...

		try {
            // 创建对象
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			// ...
			return beanInstance;
		}
		// ...
		}
	}

 

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
		// ...
		if (instanceWrapper == null) {
            // 实例化对象
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// ...
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			// ...
            // 添加至三级缓存,getEarlyBeanReference就是AOP增强过的对象引用
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// 对象初始化
		Object exposedObject = bean;
		try {
            // 解析依赖
			populateBean(beanName, mbd, instanceWrapper);
            // 初始化实例
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		// ...
		return exposedObject;
	}

 2.1.5 解析依赖

// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		// ...
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    // 利用后置处理器来处理@autowire自动注入的情况(org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor)
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
		// ...
	}

2.1.6 后置处理器处理@autowire依赖问题

// org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		// ...
		return pvs;
	}

 

// org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			    // ...
				try {
                    // 处理依赖的bean
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
				// ...
			
		}

2.1.7 后面就开启套娃模式

不断调用doGetBean,获取需要依赖的Bean,直到最后递归出来。

2.2 什么时候对象进二级缓存

如果没出现循环依赖情况,则Bean对象直接从三级缓存到一级缓存。相反,如果出现循环依赖情况,例如A依赖B,B依赖A,则解析B依赖的时候,势必会再次调用getSingleton方法,将A对象从三级缓存移至二级缓存。

// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
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)) {
            // 出现循环依赖时,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.3 什么时候对象进一级缓存

// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			    // ...
				if (newSingleton) {
                    // 移除二级、三级缓存对象信息,添加至一级缓存
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

3. FAQ

3.1 普通的循环依赖和AOP的循环依赖有什么区别

3.2 构造方法和实例化对象有什么关系

构造方法的作用就是配合new实例化一个该类的对象,至于在继承中,实例化子类对象时仅仅是调用了父类构造函数而已,并没有实例化父类对象。

3.3 AOP与Bean循环依赖为什么有紧密联系

3.4 Spring不能解决所有的循环依赖问题?

构造器注入倒置的循环依赖问题,Spring会直接抛出异常。

4. 参考资料

Spring 的循环依赖:真的必须非要三级缓存吗?

spring为什么要使用三级缓存解决循环依赖

[Spring源码解析]Spring解决bean的循环依赖问题为何需要三级缓存,而不是两级缓存?

框架源码专题:SPRING是如何解决循环依赖的?为什么无法解决多例和构造器的循环依赖

为什么Spring要使用三级缓存解决循环依赖?

Spring三级缓存

Spring 源码分析之 Spring 三级缓存解决循环依赖问题

一文告诉你Spring是如何利用"三级缓存"巧妙解决Bean的循环依赖问题的【享学Spring】

深入理解Spring循环依赖----删除三级缓存,二级缓存可不可以放代理对象和普通对象?

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值