@Async和循环依赖导致启动报错+解决(The dependencies of some of the beans in the application context form a cycle)

1.问题

今天解决了一个规范问题,代码中有一个地方使用了Thread直接起了一个异步现场,要改成放进公共线程

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

   org.springframework.scheduling.annotation.ProxyAsyncConfiguration
      ↓
   asyncConfig defined in file [***********\config\AsyncConfig.class]
      ↓
   myAsyncExceptionHandler defined in file [***********\config\MyAsyncExceptionHandler.class]
┌─────┐
|  oldServiceImpl defined in file [***********\service\Impl\OldServiceImpl.class]
↑     ↓
|  asyncServiceImpl (field private ***********.service.OldService ***********.service.Impl.AsyncServiceImpl.oldService)
└─────┘

那好,我第一步就把下面<原代码>部分改成<问题代码>

然后就启动报错了,报错内容就是循环依赖

UnsatisfiedDependencyException
BeanCurrentlyInCreationException

我想我没使用构造器啊,用@Autowired了Spring不是可以解决循环依赖吗

~

2.分析原因

那我就看一下源码,网上找一下有没有类似的问题

2.1 为什么使用@Autowired后还出现循环依赖报错

带有@Transactional和@Async的循环依赖问题

跟代码看完可知,一个类有同时有循环依赖和** @Async **的情况时,会生成两个不同的代理对象,一个是异步的代理对象,就会导致代码在AbstractAutowireCapableBeanFactory.doCreateBean方法中直接抛出错误

2.2 注解在属性上的@Lazy如何解决循环依赖

@Autowired 注入时配合@lazy是怎么起作用的

跟着源码看了一下,核心意思就是在Spring初始化ioc容器时,使用@Lazy的属性可以不加载,这样启动不报错,运行时再加载

~

3.解决

我使用了方案一,就把下面<问题代码>部分改成<正确代码>

3.1 方案一 使用属性注入时添加@Lazy延时加载

在其中一个@Autowired加了@Lazy就可以了,那么在Spring首次填充属性populateBean时,可以忽略被@Lazy注解的属性,后面使用的时候再注入

3.2 方案二 把allowRawInjectionDespiteWrapping设置为true

@Component
public class FlagChange implements BeanFactoryPostProcessor {
    
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowRawInjectionDespiteWrapping(true);
    }
}

但是这样会导致@Async失效,因为就想分析原因里写的,两个不同的对象变成同一个了

3.3 方案三 使用AopContext.currentProxy调用本类方法

AopContext.currentProxy()可以,也可以自己走一下代理创建

~

4.代码

4.1 原代码

@Service
public class OldService {
    
    

    public void initHandler(){
    
    
        new Thread(() -> hanlder()).start();
    }
    
    public void hanlder(){
    
    
        
    }
}

4.2 问题代码

@Service
public class OldService {
    
    
    @Autowired
    private AsyncService asyncService;

    public void initHandler(){
    
    
        asyncService.asyncHandler();
    }
    
    public void hanlder(){
    
    
        
    }
}
@Service
public class AsyncService {
    
    
    @Autowired
    private OldService oldService;

    @Async
    public void asyncHandler(){
    
    
        oldService.hanlder
    }
}

4.3正确代码

@Service
public class OldService {
    
    
    @Autowired
    @Lazy
    private AsyncService asyncService;

    public void initHandler(){
    
    
        asyncService.asyncHandler();
    }
    
    public void hanlder(){
    
    
        
    }
}
@Service
public class AsyncService {
    
    
    @Autowired
    private OldService oldService;

    @Async
    public void asyncHandler(){
    
    
        oldService.hanlder
    }
}

参考

带有@Transactional和@Async的循环依赖问题

@Autowired 注入时配合@lazy是怎么起作用的

Spring 使用@Async出现循环依赖Bean问题

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

猜你喜欢

转载自blog.csdn.net/weixin_43859729/article/details/109166765