@Async注解的坑
@Async注解遇上循环依赖,Spring无法解决
场景复现
AService 和 BService 相互引用,AService的 save() 方法加了 @Async 注解。
@Component
public class AService {
@Resource
private BService bService;
@Async
public void save() {
}
}
@Component
public class BService {
@Resource
private AService aService;
}这段代码会报BeanCurrentlyInCreationException异常。
将@Async注解去掉之后,再次启动项目,项目成功起来。
问题结论
spring 已经默认解决了循环依赖,但是@Async导致的循环依赖无法解决。
分析
AsyncAnnotationBeanPostProcessor 没有实现 getEarlyBeanReference
它的代理逻辑只在:
org.springframework.aop.framework.AbstractAdvisingBeanPostProcessor#postProcessAfterInitialization
//初始化完成后才创建代理
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor != null && !(bean instanceof AopInfrastructureBean)) {
if (bean instanceof Advised) {
Advised advised = (Advised)bean;
if (!advised.isFrozen() && this.isEligible(AopUtils.getTargetClass(bean))) {
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
} else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
if (this.isEligible(bean, beanName)) {
ProxyFactory proxyFactory = this.prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
this.evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
this.customizeProxyFactory(proxyFactory);
ClassLoader classLoader = this.getProxyClassLoader();
if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {
classLoader = ((SmartClassLoader)classLoader).getOriginalClassLoader();
}
return proxyFactory.getProxy(classLoader);
} else {
return bean;
}
} else {
return bean;
}
}而循环依赖发生在初始化之前(属性注入阶段),此时:
A 还没走到
postProcessAfterInitializationB 拿到的是 A 的原始对象(raw bean)
调用
a.asyncMethod()→ 同步执行!代理未生效!
解决办法
1、调整对象间的依赖关系,从根本上杜绝循环依赖,没有循环依赖,就没有早期暴露这么一说,那么就不会出现问题。
2、不使用@Async注解,可以自己通过线程池实现异步,这样没有@Async注解,就不会在最后生成代理对象,也就不会导致跟早期暴露出去的对象不一样。
3、可以在循环依赖注入的字段上加@Lazy注解。
Last updated
Was this helpful?