@Async带来的循环依赖问题

前言

需要用的springBean的生命周期和AOP的源码知识,迷茫的猿友可以自行上网查阅。

源码剖析spring bean生命周期

源码剖析springAOP的执行流程(注解方式启动spring)

spring事务源码剖析(注解方式启动spring)

描述

spring解决了单例的循环依赖,但当循环依赖的bean中出现@Async时,就会抛出异常

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-05-20 22:52:21.202 [TID:N/A] [] [main] ERROR o.s.boot.SpringApplication -Application run failed
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'activityAlarmNoticeService': Bean with name 'A' has been injected into other beans [B] 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.
  

原因

@EnableAsync -> 
@Import({AsyncConfigurationSelector.class}) -> 
ProxyAsyncConfiguration -> 
AsyncAnnotationBeanPostProcessor

@Async的后置处理器为AsyncAnnotationBeanPostProcessor

而bean的生命周期中从三级缓存获取代理对象的发放中做了判断

举例

假设AB循环依赖,A加入了@Async

1.context.getBean(A)开始创建A,A实例化完成后给A的依赖属性b开始赋值~
2.context.getBean(B)开始创建B,B实例化完成后给B的依赖属性a开始赋值~
3.重点:此时因为A支持循环依赖,所以会执行A的getEarlyBeanReference方法得到它的早期引用。而执行getEarlyBeanReference()的时候因为@Async根本还没执行,所以最终返回的仍旧是原始对象的地址
4.B完成初始化、完成属性的赋值,此时属性field持有的是Bean A原始类型的引用~
5.完成了A的属性的赋值(此时已持有B的实例的引用),继续执行初始化方法initializeBean(...),在此处会解析@Aysnc注解,从而生成一个代理对象,所以最终exposedObject是一个代理对象(而非原始对象)最终加入到容器里~
6.尴尬场面出现了:B引用的属性A是个原始对象,而此处准备return的实例A竟然是个代理对象,也就是说B引用的并非是最终对象(不是最终放进容器里的对象)
7.执行自检程序:由于allowRawInjectionDespiteWrapping默认值是false,表示不允许上面不一致的情况发生,so最终就抛错了~

依赖自检

拓展

@Transactional也会生产代理对象,为什么不会有这个问题

@EnableTransactionManagement->
@Import({TransactionManagementConfigurationSelector.class})->
ProxyTransactionManagementConfiguration->
TransactionInterceptor

 spring的声明式事务本质上就是AOP的一个通知,而AOP的后置处理器类图如下:

@TransactionInterceptor->
@Import({AspectJAutoProxyRegistrar.class})->
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)->
registerAspectJAnnotationAutoProxyCreatorIfNecessary->
AnnotationAwareAspectJAutoProxyCreator

符合判断,获取的代理对象是同一个

 

欢迎大家和帝都的雁积极互动,头脑交流会比个人埋头苦学更有效!共勉!

公众号:帝都的雁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值