06 Spring 源码总结 - 循环依赖

循环依赖的产生

假定两个类 A ,B,A 中存在 b 属性,B 中存在 a 属性
在这里插入图片描述
当对象实例化完成之后,要开始进行初始化赋值操作了,但是赋值的时候,值的类型可能是引用类型,则需要从spring容器中获取具体的对象来完成赋值操作,而此时,需要引用的对象可能被创建了,也可能没被创建。如果被创建了,那么直接获取即可,如果没有创建,在整个过程中就会涉及到对象的创建过程,而内部对象的创建过程中又会有其他的依赖,其他的依赖中可能包含当前的对象,而此时当前的对象还没有创建完成,所以此时就会产生了循环依赖问题。

在这里插入图片描述

如何解决循环依赖

  1. 实例化和初始化是分开处理的,当完成实例化之后就可以让其他对象引用当前对象,只不过当前对象不是一个完整对象而已,后续需要完成此对象的剩余步骤
  2. 直接获取半成品对象的引用地址,保证对象能够被找到,而半成品对象在堆空间中是否有设置的属性值,无所谓

构造器循环依赖

通过构造器注入的循环依赖,此依赖是无法解决的。构造器中循环依赖的注入会导致无法完成实例化,只能抛出 BeanCurrentlyInCreationException 异常

setter 循环依赖

对于 setter 注入照成的依赖是通过Spring 容器提前暴露刚完成构造器注入但未完成其他步骤的bean来完成的,只能解决单例作用域的bean循环依赖

prototype 范围的依赖处理

对于 prototype 作用域的 bean,Spring 容器无法完成依赖注入,因为Spring 容器不缓存 prototype 作用域的 bean,因此无法提前暴露一个创建中的bean

三级缓存

在这里插入图片描述

  • 一级缓存 singletonObjects
    存放创建完成完整的对象
  • 二级缓存 earlySingletonObjects
    存放完成实例化但是未完成初始化的对象
  • 三级缓存 singletonFactories
    存放创建实例的 ObjectFactory 工厂,返回普通对象或代理对象
// 为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		// 默认最终公开的对象是bean,通过createBeanInstance创建出来的普通对象
		Object exposedObject = bean;
		// mbd的systhetic属性:设置此bean定义是否是"synthetic",一般是指只有AOP相关的pointCut配置或者Advice配置才会将 synthetic设置为true
		// 如果mdb不是synthetic且此工厂拥有InstantiationAwareBeanPostProcessor
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			// 遍历工厂内的所有后处理器
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				// 如果bp是SmartInstantiationAwareBeanPostProcessor实例
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					// 让exposedObject经过每个SmartInstantiationAwareBeanPostProcessor的包装
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		// 返回最终经过层次包装后的对象
		return exposedObject;
	}

Bean 创建的大致流程

在这里插入图片描述

  1. 创建 A 对象,实例化完成后populateBean()执行前存入三级缓存
  2. A 初始化,开始属性注入 b
  3. 创建 B 对象,实例化完成后populateBean()执行前存入三级缓存
  4. B 初始化,开始属性注入 a
  5. 从 一级缓存,二级缓存,三级缓存中依次获取 Bean A
  6. 从三级缓存中找到后,调用 objectFactory :: getObject 方法
  7. 得到 A 的代理对象,存入二级缓存中,并从三级缓存中删除,
  8. B 完成实例化,存入一级缓存,从二级缓存、三级缓存中删除
  9. A 完成实例化,存入一级缓存,从二级缓存、三级缓存中删除

源码解析

getSingleton(String beanName, boolean allowEarlyReference)

从三个缓存中获取单例对象顺序是一级、二级、三级

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		// 从单例对象缓存中获取beanName对应的单例对象
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			//从早期单例对象缓存中获取单例对象(之所称成为早期单例对象,是因为earlySingletonObjects里
			// 的对象的都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)
			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) {
							// 当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								// 如果存在单例对象工厂,则通过工厂创建一个单例对象
								singletonObject = singletonFactory.getObject();
								// 记录在缓存中,二级缓存和三级缓存的对象不能同时存在
								this.earlySingletonObjects.put(beanName, singletonObject);
								// 从三级缓存中移除
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

getSingleton(String beanName, ObjectFactory<?> singletonFactory)

从一级缓存获取对象,若没有则创建一个

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		// 如果beanName为null,抛出异常
		Assert.notNull(beanName, "Bean name must not be null");
		// 使用单例对象的高速缓存Map作为锁,保证线程同步
		synchronized (this.singletonObjects) {
			// 从单例对象的高速缓存Map中获取beanName对应的单例对象
			Object singletonObject = this.singletonObjects.get(beanName);
			// 如果单例对象获取不到
			if (singletonObject == null) {
				// 如果当前在destorySingletons中
				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);
				// 表示生成了新的单例对象的标记,默认为false,表示没有生成新的单例对象
				boolean newSingleton = false;
				// 有抑制异常记录标记,没有时为true,否则为false
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				// 如果没有抑制异常记录
				if (recordSuppressedExceptions) {
					// 对抑制的异常列表进行实例化(LinkedHashSet)
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 从单例工厂中获取对象
					singletonObject = singletonFactory.getObject();
					// 生成了新的单例对象的标记为true,表示生成了新的单例对象
					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.
					// 同时,单例对象是否隐式出现 -> 如果是,请继续操作,因为异常表明该状态
					// 尝试从单例对象的高速缓存Map中获取beanName的单例对象
					singletonObject = this.singletonObjects.get(beanName);
					// 如果获取失败,抛出异常
					if (singletonObject == null) {
						throw ex;
					}
				}
				// 捕捉Bean创建异常
				catch (BeanCreationException ex) {
					// 如果没有抑制异常记录
					if (recordSuppressedExceptions) {
						// 遍历抑制的异常列表
						for (Exception suppressedException : this.suppressedExceptions) {
							// 将抑制的异常对象添加到 bean创建异常 中,这样做的,就是相当于 '因XXX异常导致了Bean创建异常‘ 的说法
							ex.addRelatedCause(suppressedException);
						}
					}
					// 抛出异常
					throw ex;
				}
				finally {
					// 如果没有抑制异常记录
					if (recordSuppressedExceptions) {
						// 将抑制的异常列表置为null,因为suppressedExceptions是对应单个bean的异常记录,置为null
						// 可防止异常信息的混乱
						this.suppressedExceptions = null;
					}
					// 创建单例后的回调,默认实现将单例标记为不在创建中
					afterSingletonCreation(beanName);
 				}
				// 生成了新的单例对象
				if (newSingleton) {
					// 将beanName和singletonObject的映射关系添加到该工厂的单例缓存中:
					addSingleton(beanName, singletonObject);
				}
			}
			// 返回该单例对象
			return singletonObject;
		}
	}

addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)

存入三级缓存

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		// 使用singletonObjects进行加锁,保证线程安全
		synchronized (this.singletonObjects) {
			// 如果单例对象的高速缓存【beam名称-bean实例】没有beanName的对象
			if (!this.singletonObjects.containsKey(beanName)) {
				// 将beanName,singletonFactory放到单例工厂的缓存【bean名称 - ObjectFactory】
				this.singletonFactories.put(beanName, singletonFactory);
				// 从早期单例对象的高速缓存【bean名称-bean实例】 移除beanName的相关缓存对象
				this.earlySingletonObjects.remove(beanName);
				// 将beanName添加已注册的单例集中
				this.registeredSingletons.add(beanName);
			}
		}
	}

addSingleton(String beanName, Object singletonObject)

存入一级缓存

protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			// 将映射关系添加到单例对象的高速缓存中
			this.singletonObjects.put(beanName, singletonObject);
			// 移除beanName在单例工厂缓存中的数据
			this.singletonFactories.remove(beanName);
			// 移除beanName在早期单例对象的高速缓存的数据
			this.earlySingletonObjects.remove(beanName);
			// 将beanName添加到已注册的单例集中
			this.registeredSingletons.add(beanName);
		}
	}

总结

本文介绍了循环依赖出现的场景与spring中的解决方法,如单纯为了解决循环依赖问题,那么使用二级缓存就可以了,三级缓存存在的意义是为了代理对象

Spring使用@Async出现循环依赖原因以及解决方案

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小刘说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值