因为在实际业务开发中像循环依赖、类内方法调用(会引起@Async不生效)等情况并不能避免
异步方法和调用类不要在同一个类中, 将@Async注解的方法,移到其它类中
如果B(versionSpPackageService)注入了A(distPlanService),A注入了B, 此时A中增加一个异步方法(被@Async标注的方法) 这种情况spring不能帮你解决循环依赖,此时重启项目导致报错:前因后果,需要去分析源码,这里我用别人总结的话简单说一下
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,表示不允许上面不一致的情况发生,最终就抛错了。
我的解决方法:
(1)重新建class,把@Async的方法放在新的类中,从根本上消除循环依赖 不要让 @Async 的 Bean 参与循环依赖
JAVA:@Async失效(测试@Async是否生效)
JAVA:@Async失效(测试@Async是否生效)_我的麦的博客-CSDN博客
// 并行流使用的并发数是 CPU 核心数,不能局部更改。全局更改影响较大,斟酌
streamList.parallelStream().forEach(consumer);