聊一聊Spring中Bean的循环依赖那些事

在Spring中Bean的循环依赖是一个非常重要的知识点,特别是在最近的工作中遇到过,因Bean的循环依赖问题而踩到的一个坑、坑、坑!!!(重要的事情说三遍),同时也想着为下一篇埋一个伏笔,本文主要还是以Bean的循环依赖原理方面展开论述。

1、Bean对象创建过程

通过以下简要的流程图,加深对Bean对象创建流程的理解。

Bean对象的创建执行过程

2、Bean对象之间循环依赖的产生

产生的原因:可能因某种业务的需求,开发人员在代码编写时会存在如下情况:

  1. ServcieA依赖于ServiceB,而ServiceB依赖ServiceA。
  2. ServiceA依赖于ServiceA(Bean对象的自我依赖)。
  • 如下图所示
    Bean对象之间循环依赖的产生

Spring中默认对象与对象之间是不允许存在相互依赖的,但是本身提供了Bean对象之间相互依赖的解决方案,即就是通过参数配置进行控制:spring.main.allow-circular-references = true , 默认是false。

3、采用三级缓存解决Bean之间循环依赖

// 一级缓存(用来存放已经初始化好的Bean)
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

// 二级缓存(用来存放Bean的早期引用)
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

// 三级缓存(用来存放Bean对应的ObjectFactory,即获取Bean的早期引用)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

3.1 Bean存入三级缓存中

/*  
 * 存入三级缓存条件:对象是单例 && 当前beanName处于创建中 && this.allowCircularReferences = true
 * this.allowCircularReferences 由setting spring.main.allow-circular-references属性控制
 */ 
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
	if (logger.isTraceEnabled()) {
		logger.trace("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
	/**
	 * addSingletonFactory()方法逻辑:
	 *  1、当前beanName添加至三级缓存中
	 *  2、当前beanName从二级缓存中移除
	 *  3、当前beanName添加至this.registeredSingletons中
	 * 
	 * ObjectFactory<?> singletonFactory 为函数式接口,在调用ObjectFactory的getObject方法时,开始调用getEarlyBeanReference()方法(该方法终端标记下)
	 */
	addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

3.2 Bean对象之间存在属性注入流程图

Bean对象之间存在属性注入流程图

如上图所示,经过分析可以得到:
当不存在循环依赖时,二级缓存和三级缓存都没有用到,只有当存在循环依赖时,才会需要二级缓存和三级缓存。

3.3 从三级缓存中获取引用对象

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 从一级缓存中获取bean
		Object singletonObject = this.singletonObjects.get(beanName);
		// 一级缓存获取为空 且 当前beanName正在创建中 时 需要从二级缓存中获取
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		// 从二级缓存中获取bean
			singletonObject = this.earlySingletonObjects.get(beanName);
			// 二级缓存为空 且 allowEarlyReference 等于 true时
			if (singletonObject == null && allowEarlyReference) {				
			 	// DCL : 二次校验当前bean是否为空
				synchronized (this.singletonObjects) {
					// 一级缓存获取Bean
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						// 二级缓存获取Bean
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
						// 三级缓存中获取Bean
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							// singletonFactory 不为空时 通过getObject()方法获取增强后的对象实例
							if (singletonFactory != null) {
								// 调用getObject方法实际上 调用:getEarlyBeanReference()方法获取代理bean
								singletonObject = singletonFactory.getObject();
								// 得到代理bean 存储到二级缓存中
								this.earlySingletonObjects.put(beanName, singletonObject);
								// 移除三级缓存
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

4、Spring中AOP增强处理

4.1 基于SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference()方法

主要实现类:AbstractAutoProxyCreator, 类图关系如下

在这里插入图片描述

public Object getEarlyBeanReference(Object bean, String beanName) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		// 存储早期代理Bean的引用
		this.earlyProxyReferences.put(cacheKey, bean);
		// 执行返回AOP代理后的bean
		// 主要处理:
		// 1、基于AnnotationAwareAspectAutoProxyCreator,即针对与AOP切面,对应注解:@AspectJ
		// 2、基于事务注解:@Transactional
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

经过上述代码分析可知。会存在以下两种情况(即存入二级缓存的对象)
1、通过AOP增强,则存入原始bean引用创建的代理对象。
2、没有AOP增强,则存入原始bean引用。
以上两点也是开头提到的坑的主要原因!!!

4.2 主要判断是否生成代理的主要实现类AopUtils#canApply()

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}

		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}

		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}
		
		// 获取当前Bean的class对象,目的是为了获取目标类对象的所有方法
		Set<Class<?>> classes = new LinkedHashSet<>();
		if (!Proxy.isProxyClass(targetClass)) {
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

		for (Class<?> clazz : classes) {
			Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
			// 遍历所有方法 查看目标类对象上或方法上是否matches方法是否为true
			for (Method method : methods) {
				if (introductionAwareMethodMatcher != null ?
						introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
						methodMatcher.matches(method, targetClass)) {
					// 为true时,表示此时需要生成代理对象
					return true;
				}
			}
		}
		return false;
	}

4.3 BeanPostProcessor的postProcessBeforeInitialization方法

主要实现类:AsyncAnnotationBeanPostProcessor,类图关系如下:

在这里插入图片描述

public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (this.advisor == null || bean instanceof AopInfrastructureBean) {
			// Ignore AOP infrastructure such as scoped proxies.
			return bean;
		}
		
		/**
		 * isEligible方法的核心逻辑为:AopUtils.canApply()方法
		 */
		if (bean instanceof Advised) {
			Advised advised = (Advised) bean;
			if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
			
				if (this.beforeExistingAdvisors) {
					advised.addAdvisor(0, this.advisor);
				}
				else {
					advised.addAdvisor(this.advisor);
				}
				return bean;
			}
		}
		/**
		 * isEligible方法的核心逻辑为:AopUtils.canApply()方法
		 * 
		 * 若isEligible返回为false时,则表示无需代理
		 */
		if (isEligible(bean, beanName)) {
			// 如下为创建代理类对象的相关逻辑
			ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
			if (!proxyFactory.isProxyTargetClass()) {
				evaluateProxyInterfaces(bean.getClass(), proxyFactory);
			}
			proxyFactory.addAdvisor(this.advisor);
			customizeProxyFactory(proxyFactory);

			// Use original ClassLoader if bean class not locally loaded in overriding class loader
			ClassLoader classLoader = getProxyClassLoader();
			if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {
				classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
			}
			return proxyFactory.getProxy(classLoader);
		}

		// No proxy needed.
		return bean;
	}

4.4 AnnotationAwareAspectJAutoProxyCreator的postProcessAfterInitialization()方法

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 此处由于getEarlyBeanReference()方法在执行的时候添加了早期引用
			// 所以,此处传入的bean和this.earlyProxyReferences.remove(cacheKey)获得的bean 是同一个
			// 也可以理解为没有执行wrapIfNecessary()方法
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 执行生成代理对象
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

4.5 Bean初始化完成后核心代码解读

/**
 * Bean完成初始化之后核心代码解析,
 * 当早期引用的Bean和初始化后的Bean不相等时,会报Bean的循环依赖异常BeanCurrentlyInCreationException
 */
if (earlySingletonExposure) {
/**
 * 此处是从一(二)级缓存中获取对象,主要还是从二级获取,
 * 因为参数allowEarlyReference==false
 */
Object earlySingletonReference = getSingleton(beanName,false);
	if (earlySingletonReference != null) {
		if (exposedObject == bean) {
			// 此处是AOP切面支持对象循环依赖的原因
			// earlySingletonReference:是从二级缓存获得的bean (代理bean对象或原始引用对象)
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

综上所述,我从四个方面解读了Spring中循环依赖的工作原理,若是能从上往下阅读,相信你对循环依赖这块也会有一定的掌握,本篇文章主要是针对原理和疑点方面进行解读,并不是结合所有代码进行方方面面的研读,这一方面希望童鞋们能够知道,具体的源码方面研读的话,到后面有时间的话,抽出核心部分研读再分享出来。

这篇文章我也是经过了两周时间的研读,有不对的地方望童鞋们批评指正! 若是有帮助到您,希望您能帮忙转发和点赞哦,说明我的辛苦没有白费,后面我也会继续努力,提升自己,进而输出更多的干货啦!
在这里插入图片描述

  • 25
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值