@Async错误使用导致Spring循环依赖报错

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

注:首先如果程序中出现了循环依赖本身就是程序设计存在问题,尽量在设计上避免出现循环依赖。在springboot框架中已经默认不支持循环依赖的存在了,除非设置spring.main.allow-circular-references=true

一、问题概述

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 ‘getBeanNamesOfType’ with the ‘allowEagerInit’ flag turned off, for example.

上面这句异常是在spring容器中某个bean存在多个版本时抛出的错误,出现在代码中存在bean的循环依赖时。但是spring明明利用三级缓存机制解决了循环依赖问题为什么还会出现这种报错呢?接下来我们通过代码复现+源码分析彻底弄懂这个问题。同时论证下三级缓存的优点,为什么不用二级缓存。

存在Messenger和ServiceA,Messenger中定义了通知第三方的消息逻辑send(),ServiceA中定义了主要业务逻辑method(),要求send()不能影响method()的响应时长故需要对send()方法做异步处理添加了 @Async注解。

@Service
public class ServiceA {
    @Autowired
    private Messenger messenger;

    @Transactional
    public void method(){
        // 主要业务
        // 不重要通知
        messenger.send();
    }
}

------------------------------------
@Service
public class Messenger {

    @Autowired
    private ServiceA serviceA;

    @Async
    public void send(){
        // 通知逻辑
		//...
    }

    @Transactional
    public void transaction(){

    }


}

现在对如上逻辑进行初始化分析,若不带@Aysnc注解按spring正常的循环依赖处理步骤应该如下图所示。
在这里插入图片描述

若带 @Async注解程序运行时会发现报错如下:

	org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'messenger': Bean
with name 'messenger' has been injected into other beans [serviceA] 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.

若带 @Async注解的初始化流程图如下:

在这里插入图片描述

上面报错换成人话:在步骤7时已经将三级缓存中提前暴露的messenger进行代理增强移入二级缓存并且注入到ServiceA中了。但是在步骤12时messenger由于@Async注解被AsyncAnnotationBeanPostProcessor后置处理器进行代理增强,且与二级缓存中的messenger代理增强不相等,若将步骤12产生的messenger代理增强作为最终版本,则ServiceA的messenger不是最终版本,此时在spring容器中存在messenger的两个版本。

二、源码分析

接下来针对关键步骤进行源码分析,需要有spring源码基础

步骤7

步骤7的上一步是,初始化ServiceA是需要注入Messenger属性,此时从容器中获取Messenger。
接下来看从容器中获取Messenger的核心方法DefaultSingletonBeanRegistry.getSingleton()

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 一级缓存中获取Messenger
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 一级缓存中未获取到Messenger
			synchronized (this.singletonObjects) {
				// 在二级缓存获取
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					// 二级缓存没获取到,在三级缓存中获取
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 执行存入三级缓存时预设的lamda表达式增强方法
						singletonObject = singletonFactory.getObject();
						// 放入二级缓存,清空三级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

Messenger因为在步骤2是提前暴露放入到了三级缓存中,所以在此出三级缓存中可以获取到Messenger,三级缓存中放置的是ObjectFactory,调用其getObject方法获取Messenger的增强代理对象。
AbstractAutowireCapableBeanFactory.getEarlyBeanReference()

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
		Object exposedObject = bean;
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			// 遍历全部的BeanPostProcessor,如果其实现了SmartInstantiationAwareBeanPostProcessor接口则调用其getEarlyBeanReference方法对bean进行早期增强
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
				   // 这里调用AnnotationAwareAspectJAutoProxyCreator.getEarlyBeanReference()
					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

AnnotationAwareAspectJAutoProxyCreator.getEarlyBeanReference() ——》AbstractAutoProxyCreator.getEarlyBeanReference()

@Override
	public Object getEarlyBeanReference(Object bean, String beanName) {
		// 获取bean的缓存key
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		// 将bean代理前的值记录于缓存,代表这个bean因为循环依赖的缘故已经被AnnotationAwareAspectJAutoProxyCreator提前进行了代理增强,在后续步骤12时可以根据缓存判断是否已被提前增强,避免被AnnotationAwareAspectJAutoProxyCreator进行重复代理增强。
		this.earlyProxyReferences.put(cacheKey, bean);
		// 获取代理增强对象
		return wrapIfNecessary(bean, beanName, cacheKey);
	}

获取代理增强对象流程在后面分析。

步骤12

此时Messenger完成了创建、参数注入过程,在步骤12进行初始化和bean的前置后置处理。
AbstractAutowireCapableBeanFactory.initializeBean()

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			// 执行bean实现的各种Aware接口如:BeanNameAware/BeanFactoryAware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// 执行bean的处理器中的before方法
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			// 调用初始化方法如 实现InitializingBean接口的afterPropertiesSet方法,和xml中指的的init-method
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
			// 执行bean的后置处理器中的方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

这里主要看下执行bean的后置处理

@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			// 这里的getBeanPostProcessors()包含AnnotationAwareAspectJAutoProxyCreator和AsyncAnnotationBeanPostProcessor
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

AnnotationAwareAspectJAutoProxyCreator后置处理器由于在步骤7时已经对Messenger进行了提前增强,所以在此处返回对象本身不会进行重复增强了。AsyncAnnotationBeanPostProcessor却会对Messenger进行代理增强,所以此处返回的current是AsyncAnnotationBeanPostProcessor产生的代理类。

首先看下AnnotationAwareAspectJAutoProxyCreator.postProcessAfterInitialization()

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 如果该对象在处理循环依赖时三级缓存升级二级缓存的过程中调用getEarlyBeanReference方法进行了代理增强,earlyProxyReferences中会缓存该对象的cacheKey,
			// 所以此处为false,不会重复进行代理了
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 进行代理对象创建
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

再看下AsyncAnnotationBeanPostProcessor.postProcessAfterInitialization(),因为AnnotationAwareAspectJAutoProxyCreator未对Messenger进行代理增强所以此处返回的是一个被AsyncAnnotationBeanPostProcessor增强的Messenger的代理类。

public Object postProcessAfterInitialization(Object bean, String beanName) {
		// 是否是AOP的基础建设类,即springAOP原生的类,不做任何处理
		if (this.advisor == null || bean instanceof AopInfrastructureBean) {
			// Ignore AOP infrastructure such as scoped proxies.
			return bean;
		}
		// 是否是AOP代理类
		if (bean instanceof Advised) {
			Advised advised = (Advised) bean;
			if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
				// Add our local Advisor to the existing proxy's Advisor chain...
				// 将当前后置处理器中的advisor添加到当前代理对象的advisor链中
				if (this.beforeExistingAdvisors) {
					advised.addAdvisor(0, this.advisor);
				}
				else {
					advised.addAdvisor(this.advisor);
				}
				return bean;
			}
		}
		// 到此处说明当前bean非AOP代理对象,在此处进行代理增强,添加切面链
		if (isEligible(bean, beanName)) {
			ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
			if (!proxyFactory.isProxyTargetClass()) {
				evaluateProxyInterfaces(bean.getClass(), proxyFactory);
			}
			proxyFactory.addAdvisor(this.advisor);
			customizeProxyFactory(proxyFactory);
			// 返回代理对象
			return proxyFactory.getProxy(getProxyClassLoader());
		}

		// No proxy needed.
		return bean;
	}

步骤13

步骤13是spring在处理循环依赖时为了避免容器中bean的版本一致性进行的一个兜底判断逻辑。
首先看下spring创建bean、暴露三级缓存、bean参数注入、初始化及后置处理、循环依赖兜底判断的核心串联方法AbstractAutowireCapableBeanFactory.doCreateBean()方法

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			// 创建bean实例,调用构造方法,如果有定义带参构造,则自动在beanfactory获取对应类型的入参,
			// 如果beanfactory未获取到,且没有无参构造,则抛出异常  
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 是否提前暴露,就是将半成品的bean加入三级缓存,此时可以通过getBean拿到半成品的bean;
		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(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		// 初始化bean实例
		Object exposedObject = bean;
		try {
			// Bean属性填充
			populateBean(beanName, mbd, instanceWrapper);
			// 调用初始化方法/应用BeanPostProcessor后置处理器
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			// 看下二级缓存中有无已经增强过的代理类,如果有的话取出来代替现在的类
			//(因为如果出现了循环依赖某类A在三级缓存升级为二级缓存是进行了代理类增强,A类的后置处理中就不会再进行代理增强了,而是在此处获取二级缓存中的代理)
			Object earlySingletonReference = getSingleton(beanName, false);
			// 比较下后置处理后的bean还是否原来的bean如果还是说明没有进行代理增强,替换成二级缓存中的。
			if (earlySingletonReference != null) {
				if (exposedObject == 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 " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

上面方法太长了,写一段伪代码着重讲下循环依赖的兜底判断及当前场景异常抛出的原因

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
			// 步骤1.利用反射调用构造方法创建Messenger
			BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
			Object bean = instanceWrapper.getWrappedInstance();
			// 步骤2.提前暴露将Messenger保存到三级缓存singletonFactories中
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		    Object exposedObject = bean;
			// 步骤3.为Messenger注入属性ServiceA
			populateBean(beanName, mbd, instanceWrapper);
			// 步骤12.对Messenger进行初始化和bean的前置和后置处理(代理增强),因为存在@Async注解故被AsyncAnnotationBeanPostProcessor后置处理器增强,返回代理对象
			exposedObject = initializeBean(beanName, exposedObject, mbd);
			
			//步骤13.判断下二级缓存中是否存在Messenger,此处存在。然后比较步骤1中创建的Messenger与步骤12代理增强后的Messenger是否相同,此处不相同且检查到Messager已经被注入到ServiceA中此处抛出异常。
			-----------------------------------步骤13重点分析---------------------------------------------------
			// 从缓存中获取Messenger,因为步骤7,所以此处取到的是二级缓存中的被AnnotationAwareAspectJAutoProxyCreator后置处理器增强的代理对象
			Object earlySingletonReference = getSingleton(beanName, false);
				if (exposedObject == bean) {
				// 判断一下步骤12返回的对象有没有被代理增强过,如果没被增强此处应该等于步骤1创建的bean,此时将二级缓存中的代理类作为最终版本返回。(因为如果出现了循环依赖某类A在三级缓存升级为二级缓存是进行了AnnotationAwareAspectJAutoProxyCreator代理类增强,A类的后置处理中就不会再重复进行AnnotationAwareAspectJAutoProxyCreator代理增强了,而是在此处获取二级缓存中的代理,节约性能也保证了A最终版本和提前注入版本保持一致)
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
				// 因为步骤12返回的是AsyncAnnotationBeanPostProcessor后置处理器增强的代理对象,且Messenger已经在步骤7时注入到了ServiceA中所以actualDependentBeans=1。此时步骤12返回的为MessengerProxy2,ServiceA中注入的是MessengerProxy1。
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					// Messenger已经在步骤7时注入到了ServiceA中所以actualDependentBeans=1,所以抛出此异常。
					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 " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
		return exposedObject;
	}

至此异常产生的原因源码分析完毕。接下来真的几个问题在进行拓展分析。

三、问题拓展分析

3.1、先加载ServiceA为什么不报错

因为先加载ServiceA时,ServiceA中的Messenger与Messenger正常初始化后的最终版本一致

先加载ServiceA时流程如下:

  1. 创建ServiceA并提前暴露放入三级缓存
  2. 像ServiceA中注入Messenger,触发Messenger的初始化
  3. 创建Messenger并提前暴露放入三级缓存
  4. 从三级缓存中获取ServiceA进行AnnotationAwareAspectJAutoProxyCreator代理增强ServiceAProxy放入二级缓存并注入到Messenger中
  5. Messenger进行初始化、bean的前置后置处理
    • AnnotationAwareAspectJAutoProxyCreator代理增强返回MessengerProxy
    • AsyncAnnotationBeanPostProcess中判断MessengerProxy已经被代理,将自身的advisor添加至MessengerProxy
  6. 二级缓存中未获取到Messenger,将MessengerProxy作为最终版本放入一级缓存
  7. ServiceA一级缓存获取Messenger成功注入Messenger
  8. ServiceA进行初始化、bean的前置后置处理
    • 因为步骤4AnnotationAwareAspectJAutoProxyCreator已经对ServiceA进行过代理增强,所以此处返回ServiceA本身
  9. 二级缓存中获取到ServiceAProxy,判断步骤8返回的ServiceA等于步骤1的ServiceA,所以将ServiceAProxy作为最终版本放入一级缓存

3.2、为什么需要三级缓存

首先三级缓存不是spring解决循环依赖的必要条件,用二级缓存乃至一级缓存也能解决循环依赖, 只能说用三级缓存更加优雅,让程序更符合设计原则,更利于后续扩展。
首先明确循环依赖是要解决什么问题:保证bean提前暴露版本与bean后置处理完成后的最终版本一致。

一级缓存解决循环依赖

改变下bean的创建顺序:由1.创建并提前暴露原对象、2.注入属性、3.初始化、4.后置处理(代理增强) ===>> 1.创建、2.后置处理(代理增强)并提前暴露代理对象、3.注入属性、4.初始化。
像这样创建后即刻进行代理增强并将代理增强后的版本提前暴露到一级缓存中,就可以保证bean提前暴露版本与后置处理完成后的最终版本一致了,只使用一级缓存解决了循环依赖问题。

但这样做的不好之处很多随便列举几个:

  • 一级缓存中即包含完全初始化的bean又包含未完全初始化的bean,违反一级缓存设计原则。
  • 违反了spring对bean的初始化流程设计,设计本身是要先完成初始化再进行后置处理的。
  • 只用一级缓存程序的扩展型会变低
二级缓存解决循环依赖

同理用二级缓存如果接受一级缓存中即包含完全初始化的bean又包含未完全初始化的bean或者接受将代理增强提前到注入和初始化之前也能解决循环依赖。但是在设计上始终不够优雅,不合理。

3.3、为什么@Async不能直接用AnnotationAwareAspectJAutoProxyCreator处理

因为@Async相关的切面没有声明给spring管理,AnnotationAwareAspectJAutoProxyCreator在创建代理对象是无法获取
首先看下AnnotationAwareAspectJAutoProxyCreator是怎样创建代理对象的

AnnotationAwareAspectJAutoProxyCreator.wrapIfNecessary()

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		//
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 当前bean无切面,所以无需生成代理对象
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		//
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 获取当前bean相关的全部切面
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}
		// 当前bean无切面
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

只要getAdvicesAndAdvisorsForBean()能获取到对应切面就能处理对应的注解如@Transactional注解
AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors()

protected List<Advisor> findCandidateAdvisors() {
		// 在spring容器中获取Advisor,如TransactionAttributeSourceAdvisor
		List<Advisor> advisors = super.findCandidateAdvisors();
		// 添加AspectJ类型的切面并转换为advisor如:用户使用@Aspect自定义的切面
		if (this.aspectJAdvisorsBuilder != null) {
			advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		}
		return advisors;
	}

所以重点是看下处理@Async相关的切面有没有注入到spring容器,这个地方我们对比@Transactional一起看源码。

@EnableTransactionManagement

@EnableTransactionManagement注解向容器中注入了TransactionManagementConfigurationSelector
在这里插入图片描述
TransactionManagementConfigurationSelector向容器中注入了ProxyTransactionManagementConfiguration
在这里插入图片描述
ProxyTransactionManagementConfiguration向容器中注入了处理@Transactional的切面BeanFactoryTransactionAttributeSourceAdvisor,所以AnnotationAwareAspectJAutoProxyCreator后置处理器产生的代理对象切面链中包涵BeanFactoryTransactionAttributeSourceAdvisor可以处理@Transactional注解。
在这里插入图片描述

@EnableAsync

@EnableTransactionManagement注解向容器中注入了AsyncConfigurationSelector

在这里插入图片描述
AsyncConfigurationSelector像容器中注入了ProxyAsyncConfiguration
在这里插入图片描述
ProxyAsyncConfiguration像容器中注入了AsyncAnnotationBeanPostProcessor后置处理器
在这里插入图片描述
但是处理@Async的Advisor是通过初始化的方式传入AsyncAnnotationBeanPostProcessor的,并没有将@Async的Advisor注入给spring管理,所以AnnotationAwareAspectJAutoProxyCreator在生成代理对象是无法获取@Async相关的切面AsyncAnnotationAdvisor即无法处理@Async注解
在这里插入图片描述

Exception | netty | This means that said other beans do not use the final version of the bean. 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 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example. spring循环依赖 阅读详情

相关推荐

一文详解 Spring Bean 循环依赖

本文主要梳理了Spring解决bean循环依赖的思路。

阿里云云栖号 1792

This is often the result of over-eager type matching - consider using ‘getBeanNamesForType‘

碰到循环依赖的,把类之间的关系理清楚,看看哪些是相互引用了,把循环引用给断了。这样是比较好的

一路向前 5076

Spring IoC源码解析之getBean,血与泪的总结

getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } //调用真正的getBean if (isEagerInit) { getBean(beanName); } } } else {//非工厂Bean就是普通的bean getBean(beanName)

m0_64383736的博客 487

Exception | This means that said other beans do not use the final version of the bean. This is often

一、异常 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 'getBeanNamesOfType' with the 'allowEagerInit' fla...

苏老师的博客 1055

spring循环依赖使用@Async注解导致报错问题

spring的三级缓存和循环依赖

weixin_44771989的博客 782

使用@Async异步注解导致Bean循环依赖时启动报BeanCurrentlyInCreationException异常的根本原因分析,以及提供解决方案【享学Spring

前言 今天在使用@Async的时候,碰到了一个问题:Spring循环依赖(circular reference)问题。 或许说到这,有的小伙伴就会大惊失色了。Spring不是解决了循环依赖问题吗,它是支持循环依赖的呀?怎么会呢? 说实话在这之前我也这么坚信的,而且每次使用得也屡试不爽。如果你目前也和我的想法一样的坚挺,那么相信本文能让你收获不少。 Spring循环依赖最经典的一个案例:自己引用自己...

架构师:通透,才能写出好代码! 2万+

Spring源码三千问】哪些循环依赖问题Spring解决不了?

哪些循环依赖问题Spring解决不了?前言版本约定正文场景一: prototype 类型的循环依赖场景二: constructor 注入的循环依赖场景三:Proxy 类型的 Bean循环依赖小结 系列博文: 【老王读Spring IoC-0】Spring IoC 引入 【老王读Spring IoC-1】IoC 之控制反转引入 【老王读Spring IoC-2】IoC 之 BeanDefinition 扫描注册 【老王读Spring IoC-3】Spring bean 的创建过程 【老王读Spring I

老王的专栏 7291

Spring使用@Async注解后导致循环依赖问题

Spring使用@Async注解后导致循环依赖问题

啊松同学的博客 1345

Spring Boot 中使用 @Async 注解导致循环依赖的原因及解决方案

前言 在写这篇文章之前,我写了一篇关于循环依赖的文章,为什么这篇文章我又说和循环依赖有关的话题呢,其实,是因为我原本想写一篇关于 @Async 原理分析的文章的,后来为了能更深入理解 @Async 以便我接下来的写的文章,无意之间看到了 @Async 也会导致循环依赖的问题。 关于循环依赖怎么解决以及源码分析可以看我这一篇文章:Spring 源码分析如何解决喜欢依赖的问题 Spring 是允许循环依赖的,换句话说,Spring 自身是已经解决了循环依赖这个问题,但是在这里竟然又出现了。比如以下添加 @As

养歌的博客 7474

spring 第三级缓存singletonFactories的作用及@Async造成循环依赖报错原因分析

第三级缓存singletonFactories,解决不了@Async注解生成的代理类造成的循环依赖的问题。

曾令胜的博客 1103

spring】解决因@Async引起的循环依赖报错

最近在项目中使用@Async注解在方法上引起了循环依赖报错。 代码类似如下: package com.morris.spring.entity.circular; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Enabl

morris 7840

深度解析@Async引起的循环依赖

啊,昨晚发版又出现了让有头大的循环依赖问题,按理说Spring会为我们解决循环依赖,但是为什么还会出现这个问题呢?为什么在本地、UAT以及PRE环境都没有出现这个问题,但是到了PROD环境就出现了这个问题呢?本文将从事故时间线、及时止损、复盘分析等几个方面为大家带来详细的分析,干货满满! 事故时间线 本着"先止损、后复盘分析"的原则,我们来看一下这次发版事故的时间线。 2021年11月16日晚23点00分00秒开始发版,此时集团的devops有点慢 2021年11月16日晚23点03分01秒,收到发版失败

程铭程铭你快成名的博客 5701

@Async 导致循环依赖异常

@Async 导致循环依赖异常:circular reference

qq_32577829的博客 3118

@Async注解引发的报错循环依赖

@Async注解引发的报错循环依赖回顾RobotServiveImpl与TaskServiceImpl的循环依赖 回顾 我们现在正在探究循环依赖中加了@Async注解产生的错误。 报的错误是: Unsatisfied dependency expressed through field 'taskService'; nested exception is org.springframework.beans.factory. BeanCurrentlyInCreationException: Err

weixin_43810802的博客 1472

Spring 源码解析 - @Async 注解下的循环依赖问题原理

仅允许有一个实例,先创建的要被后创建的覆盖,但这个覆盖的前提是实例已经完全创建成功,这里可以看下。方法获取一个早期的实例,获取之后存入二级缓存中,从前面放入三级缓存可以看出其实是触发的。,由于这里是循环依赖,已经放入了第三级缓存中,因此可以命中,这快的源码逻辑在。实例,由于前面已经曝光到了二级缓存中,因此这里可以获取到,但容器中的。存在循环依赖,仅放入二级缓存中,并没有实例化完成,因此这里会返回。真正的实例,而这里返回的是代理实例,现在相当于单例的。是不是很奇怪,难道代理对象就会有问题吗,如果换成。

小毕超博客 1954

@Async注解导致偶发循环依赖问题产生原因

通过实现BeanDefinitionRegistryPostProcessor接口,在postProcessBeanDefinitionRegistry方法中通过BeanDefinitionRegistry获取到所有bean的注册信息,将bean保存到LinkedHashMap中,并从BeanDefinitionRegistry中删除,然后将保存的bean定义排序后,重新再注册到BeanDefinitionRegistry中,即可实现bean加载顺序的控制。

qq_37436172的博客 727

由于工作中的一次报错 引起的对Spring循环依赖的探究

由于工作中的一次报错 引起的对循环依赖的探究

小脚鱼的博客 2612

@Async注解导致循环依赖BeanCurrentlyInCreationException异常

使用@Async异步注解导致Bean循环依赖时启动报BeanCurrentlyInCreationException异常的根本原因分析,以及提供解决方案 今天在自己项目中使用@Async的时候,碰到了一个问题:Spring循环依赖(circular reference)问题。 或许刚说到这,有的小伙伴就会大惊失色了。Spring不是解决了循环依赖问题吗,它是支持循环依赖的呀?怎么会呢? 出现使用@Async导致循环依赖问题的必要条件: 已开启@EnableAsync的支持 @Async注解.

小泽 1018

使用@Async异步注解导致Bean循环依赖时启动报BeanCurrentlyInCreationException异常的根本原因分析,以及提供解决方案

前言 今天在自己工程中使用@Async的时候,碰到了一个问题:Spring循环依赖(circular reference)问题。 或许刚说到这,有的小伙伴就会大惊失色了。Spring不是解决了循环依赖问题吗,它是支持循环依赖的呀?怎么会呢? 不可否认,在这之前我也是这么坚信的,而且每次使用得也屡试不爽。倘若你目前也和我有一样坚挺的想法,那么相信本文能让你大有收货~~。 不得不提,关于@Async使用姿势,请参阅: 【小家SpringSpring异步处理@Async使用以及原理、源码分析(@Ena

hellozhxy的博客 821
上一篇: 服务第一次访问卡顿
下一篇: JVM角度看方法调用-开篇
躺平程序猿
博客等级 码龄8年 4870粉丝 71原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

躺平程序猿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值