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

简介: @Async注解导致循环依赖,BeanCurrentlyInCreationException异常

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

今天在自己项目中使用@Async的时候,碰到了一个问题:Spring循环依赖(circular reference)问题

或许刚说到这,有的小伙伴就会大惊失色了。Spring不是解决了循环依赖问题吗,它是支持循环依赖的呀?怎么会呢?

出现使用@Async导致循环依赖问题的必要条件:

  1. 已开启@EnableAsync的支持
  2. @Async注解所在的Bean被循环依赖了

为什么有小伙伴跟我说:我使用@Async即使本类方法调用也从来木有遇到这个错误啊?难道它不常见?

为此经过我的一番调查,包括看一些同事、小伙伴的代码发现:并不是使用@Async没有启动报错,而是他本类调用的时候直接调用的方法,这样@Async是不生效的但小伙伴却全然不知而已。


至于@Async没生效这种问题为何没报出来???甚至过了很久很久都没人发现和关注??

其实道理很简单,它和事务不生效不一样,@Async若没生效99%情况下都不会影响到业务的正常进行,因为它不会影响数据正确性,只会影响到性能(无非就是异步变同步呗,这是兼容的)


我们知道事务不生效和@Async不生效的根本原因都是同一个:直接调用了本类方法而非接口方法/代理对象方法。

解决这类不生效问题的方案一般我们都有两种:


自己注入自己,然后再调用接口方法(当然此处的一个变种是使用编程方式形如:AInterface a = applicationContext.getBean(AInterface.class);这样子手动获取也是可行的~~~本文不讨论这种比较直接简单的方式)

使用AopContext.currentProxy();

让不调用本类的@Async方法不就可以了;让不产生循环依赖不就可以了,这也是解决方案

1:新建一个线程池配置类AsyncConfig

@EnableAsync
@Configuration
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 
        executor.setCorePoolSize(10); //核心线程数
        executor.setMaxPoolSize(20);  //最大线程数
        executor.setQueueCapacity(1000); //队列大小
        executor.setKeepAliveSeconds(300); //线程最大空闲时间
        executor.setThreadNamePrefix("fsx-Executor-"); //指定用于新创建的线程名称的前缀。
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略(一共四种,此处省略)
 
        executor.initialize();
        return executor;
    }
 
    // 异常处理器:当然你也可以自定义的,这里我就这么简单写了~~~
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

2:新增一个HelloService接口

public interface HelloService {
    Object hello(Integer id);
    void fun1();
}

3:新增一个HelloServiceImpl实现类

@Service
public class HelloServiceImpl implements HelloService{
    @Autowired
    private HelloService helloService;
    @Override
    public Object hello(Integer id) {
        System.out.println("线程名称:" + Thread.currentThread().getName());
        helloService.fun1(); // 使用接口方式调用,而不是this
        return "service hello";
    }
 
    @Async
    @Override
    public void fun1() {
        System.out.println("线程名称:" + Thread.currentThread().getName());
    }
}

4:新增一个异步测试类

@SpringBootTest
public class AsyncTest {
    @Autowired
    private HelloService helloService;
    @Test
    public void test(){
        helloService.hello(1);
    }
}

5:启动测试类

此种做法首先是Spring中一个典型的循环依赖场景:自己依赖自己。本以为能够像解决事务不生效问题一样依旧屡试不爽,但没想到非常的不给面子,启动即报错

报错如下BeanCurrentlyInCreationException异常

6:解决方法

在HelloServiceImpl类上@Autowired注解下加上@Lazy注解,即懒加载

 

7:启动项目

输出如下,成功了

 

相关文章
|
Java Spring 容器
解决Spring的UnsatisfiedDependencyException异常的方法
在Spring开发中,UnsatisfiedDependencyException异常意味着依赖注入失败,影响应用稳定性。该异常由Spring容器在无法满足bean依赖时抛出,常见原因包括bean定义错误、循环依赖、多个候选bean等。解决方法包括:检查bean定义和注入的正确性、解决循环依赖、确认依赖包的兼容性、使用@Qualifier或@Primary注解。通过日志、调试工具和异常对比来定位问题。持续学习Spring框架有助于更好地解决此类异常。
10505 11
|
Java API 开发工具
如何用阿里云 oss 下载文件
阿里云对象存储服务(OSS)提供了多种方式下载文件,以下讲解下各种方式的下载方法
12583 2
|
6月前
|
消息中间件 监控 Kubernetes
别再乱排查了!Kafka 消息积压、重复、丢失,根源基本都是 Rebalance!
大家好,我是小富~分享一次Kafka消息积压排查经历:消费者组因Rebalance导致消费能力骤降。本文详解Rebalance触发场景(消费者变更、分区扩容、订阅变化、超时等),剖析其引发的消息积压、重复消费、丢失等问题根源,并提供优化方案:调优超时参数、手动提交offset、启用粘性分配策略、保障消费幂等性。掌握这些,轻松应对Kafka常见故障!
1270 0
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
10月前
|
人工智能 Java 数据库
如何保证接口幂等性?
在分布式系统中,接口幂等性至关重要。本文详解其定义、重要性及实现方案,包括唯一索引、Token机制、分布式锁、状态机与版本号机制,并提供最佳实践建议,助你提升系统可靠性与用户体验。
2047 1
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
2602 26
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
搜索推荐 Java 开发者
org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException 问题处理
【5月更文挑战第14天】org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException 问题处理
5878 1
|
消息中间件 安全 大数据
Kafka多线程Consumer是实现高并发数据处理的有效手段之一
【9月更文挑战第2天】Kafka多线程Consumer是实现高并发数据处理的有效手段之一
1403 5
|
SQL XML Java
Mybatis中foreach的使用
【11月更文挑战第12天】MyBatis 的 `foreach` 标签用于在 SQL 语句中遍历集合或数组,支持批量插入、更新及多条件查询等操作。通过设置 `collection`、`item` 等属性,可动态生成 SQL 片段,实现高效的数据处理。示例包括批量插入用户信息、根据 ID 列表查询用户数据以及遍历 Map 查询分类下的产品。
1277 0
下一篇
开通oss服务