Springboot中使用@Async注解7大失效场景及解决方案

Springboot中使用@Async注解7大失效场景及解决方案

  • 前言
  • 正文
    • 场景一:调用者与被调用者在同一个类中
      • 解决方案
    • 场景二:配置类未启用异步支持
      • 解决方案
    • 场景三:方法不是 public 的
      • 解决方案
    • 场景四:线程池未正确配置
      • 解决方案
    • 场景五:异常处理不当
      • 解决方案
    • 场景六:Spring代理未生效
      • 解决方案
    • 场景七:使用 @Transactional 与 @Async 同时注解方法,导致事务失效
      • 解决方案
  • 总结

前言

在Spring Boot中,@Async注解 就像一把瑞士军刀,能帮你轻松处理那些耗时的任务,让主线程可以继续忙别的事儿。不过,跟所有强大的工具一样,用不好它也可能出岔子。有时候,你可能因为 线程池没配好异常没处理好,或者 Spring代理没生效 等原因,导致@Async没按你期望的那样工作。为了避免这些坑,咱们得深入了解下@Async是怎么工作的,还要知道怎么用才能不出问题。接下来,咱们就来聊聊七种常见的@Async失效情况,还有怎么搞定它们。这样,大家在享受异步编程带来的好处时,也能心里更有底儿。

正文

场景一:调用者与被调用者在同一个类中

当调用 @Async注解 的方法的类和被调用的方法在同一个类中时,@Async 注解不会生效。因为 Spring 的 AOP 代理是基于接口的,对于同一个类中的方法调用,不会经过代理,因此 @Async 注解不会被处理。例如:

@Service  
public class MyService {  @Async  public void asyncMethod() {  // 模拟耗时操作  try {  Thread.sleep(5000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("Async method executed.");  }  public void callAsyncMethod() {  asyncMethod(); // 直接调用,不会异步执行  }  
}

解决方案

  1. 确保异步方法和调用它的方法不在同一个类中。可以将异步方法提取到一个单独的 Service 中,并在需要的地方注入这个 Service。
  2. 确保异步方法的执行类(即包含 @Async 注解方法的类)被 Spring 容器管理,比如通过 @Service、@Component 等注解标注
//一定使用@Service、@Component 等注解标注,确保执行类被Spring管理,因为异步线程是通过动态代理实现的
@Service
public class AsyncService {@Async  public void asyncMethod() {  // 模拟耗时操作  try {  Thread.sleep(5000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("Async method executed.");  }  
}

场景二:配置类未启用异步支持

如果配置类中没有启用异步支持,即没有使用 @EnableAsync 注解,那么 @Async 注解同样不会生效。

// 没有使用 @EnableAsync 注解,因此不会启用异步支持  
@Configuration  
public class AsyncConfig {  // ... 其他配置 ...  
}  @Service  
public class MyService {  @Async  public void asyncMethod() {  // 模拟耗时操作  try {  Thread.sleep(5000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("Async method executed.");  }  
}

解决方案

  1. 在配置类上使用 @EnableAsync 注解,启用异步支持。
@Configuration
@EnableAsync
public class AsyncConfig {  // ... 其他配置 ...  
}

场景三:方法不是 public 的

@Async 注解的方法必须是 public 的,否则不会被 Spring AOP 代理捕获,导致异步执行不生效。

@Service  
public class MyService {  @Async // 但这个方法不是 public 的,所以 @Async 不会生效  protected void asyncMethod() {  // 模拟耗时操作  try {  Thread.sleep(5000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("Async method executed.");  }  public void callAsyncMethod() {  asyncMethod(); // 直接调用,但由于 asyncMethod 不是 public 的,因此不会异步执行  }  
}

解决方案

  • 确保异步方法是 public 的

场景四:线程池未正确配置

在使用 @Async 注解时,如果没有正确配置线程池,可能会遇到异步任务没有按预期执行的情况。例如,线程池被配置为只有一个线程,且该线程一直被占用,那么新的异步任务就无法执行。

@Configuration  
@EnableAsync  
public class AsyncConfig implements AsyncConfigurer {  @Override  public Executor getAsyncExecutor() {  // 创建一个只有一个线程的线程池,这会导致并发问题  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();  executor.setCorePoolSize(1);  executor.setMaxPoolSize(1);  executor.setQueueCapacity(10);  executor.setThreadNamePrefix("Async-");  executor.initialize();  return executor;  }  // ... 其他配置 ...  
}@Service  
public class MyService {  @Async  public void asyncMethod() {  // 模拟耗时操作  try {  Thread.sleep(5000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("Async method executed.");  }  
}

解决方案

  • 正确配置线程池:确保线程池配置合理,能够处理预期的并发任务量

场景五:异常处理不当

如果在异步方法中抛出了异常,并且没有妥善处理,那么这个异常可能会导致任务失败,而调用者可能无法感知到异常的发生。

@Service  
public class MyService {  @Async  public void asyncMethod() {  // 模拟一个可能会抛出异常的耗时操作  throw new RuntimeException("Async method exception");  }  
}
// 调用者  
@Service  
public class CallerService {  @Autowired  private MyService myService;  public void callAsyncMethod() {  myService.asyncMethod(); // 调用异步方法,但如果该方法抛出异常,调用者不会立即感知到  }  
}

解决方案

  • 合理处理异常:在异步方法中妥善处理异常,可以通过 Future 对象来捕获异步任务执行过程中抛出的异常。

场景六:Spring代理未生效

如果通过 new 关键字直接创建了服务类的实例,而不是通过 Spring 容器来获取,那么 Spring 的 AOP 代理将不会生效,导致 @Async 注解无效。

@Service  
public class MyService {  @Async  public void asyncMethod() {  // 模拟耗时操作  try {  Thread.sleep(5000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("Async method executed.");  }  
}  public class SomeNonSpringClass {  public void someMethod() {  MyService myService = new MyService(); // 直接通过 new 创建 MyService 实例,不会经过 Spring 代理  myService.asyncMethod(); // 这里 @Async 不会生效  }  
}

解决方案

  • 合理利用依赖注入:始终通过 Spring 容器来获取服务类的实例,而不是直接通过 new 关键字创建
@Service  
public class MyService {  @Async  public void asyncMethod() {  // 模拟耗时操作  try {  Thread.sleep(5000);  } catch (InterruptedException e) {  e.printStackTrace();  }  System.out.println("Async method executed.");  }  
}  
@Service
public class SomeNonSpringClass {  @Autowired  private MyService myService;  public void someMethod() {   myService.asyncMethod(); // 这里 @Async 会生效  }  
}

场景七:使用 @Transactional 与 @Async 同时注解方法,导致事务失效

在同一个方法上同时使用 @Transactional 和 @Async 注解可能会导致问题。由于 @Async 会导致方法在一个新的线程中执行,而 @Transactional 通常需要在一个由 Spring 管理的事务代理中执行,这两个注解的结合使用可能会导致事务管理失效或行为不可预测。此种场景不会导致@Async注解失效,但是会导致@Transactional注解失效,也就是事务失效。例如:

@Service  
public class MyService {  @Autowired  private MyRepository myRepository;  // 错误的用法:同时使用了 @Transactional 和 @Async  @Transactional  @Async  public void asyncTransactionalMethod() {  // 模拟一个数据库操作  myRepository.save(new MyEntity());  // 模拟可能抛出异常的代码  if (true) {  throw new RuntimeException("Database operation failed!");  }  }  
}  @Repository  
public interface MyRepository extends JpaRepository<MyEntity, Long> {  // ...  
}  @Entity  
public class MyEntity {  // ... 实体类的属性和映射 ...  
}

上面的代码,在抛出异常的时候,我们期望的是回滚前面的数据库保存操作,但是因为事务失效,会导致错误数据成功保存进数据库。

解决方案

  • 正确配置事务,比如单独提取事务执行的逻辑到一个新的Service里,事务执行方法单独使用@Transactional标识
@Service  
public class MyService {  @Autowired  private MyTransactionalService myTransactionalService;  @Autowired  private AsyncExecutor asyncExecutor;  public void callAsyncTransactionalMethod() {  // 在事务中执行数据库操作  MyEntity entity = myTransactionalService.transactionalMethod();  // 异步执行其他操作  asyncExecutor.execute(() -> {  // 这里执行不需要事务管理的异步操作  // ...  });  }  
}  @Service  
public class MyTransactionalService {  @Autowired  private MyRepository myRepository;  @Transactional  public MyEntity transactionalMethod() {  // 在事务中执行数据库操作  return myRepository.save(new MyEntity());  }  
}  @Component  
public class AsyncExecutor {  @Async  public void execute(Runnable task) {  task.run();  }  
}

总结

这里面,绝大多数人会遇到的坑点主要会集中在没有配置自定义线程池、异步方法在同一个类中调用、事务不起作用这几个问题上。所以,万金油的写法还是专门定义一个AsyncService,将异步方法都写在里面,需要使用的时候,就在其他类将其注入即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/758055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Combining external-latent attention for medical image segmentation

结合外部潜在注意的医学图像分割 摘要 注意机制是提高医学图像分割性能的新切入点。如何合理分配权重是注意力机制的关键,目前流行的方法包括全局压缩和使用自注意操作的非局部信息交互。然而,这些方法过于关注外部特征,缺乏对潜在特征的开发。全局压缩方法通过全局均值或…

C01 C++ Modding

Modding Programs running on a user-controlled computer are amenable to “modding” . If a piece of information, such as an integer representing health or lives, exists in RAM, one may find and edit it to their liking. Taken to the extreme, entirely new …

threejs 模型聚焦定位

需求&#xff1a;鼠标选中模型&#xff0c;然后点击定位按钮&#xff0c;将相机平移到模型跟前&#xff0c;相机视线不变 var box new THREE.Box3();//包围盒box.expandByObject(model);//model是模型var center new THREE.Vector3();box.getCenter(center);//获取中心点var …

测试人员如何进行需求分析?

在进行测试用例设计之前&#xff0c;我们通常需要对需求文档进行分析&#xff0c;甚至在需求评审阶段从测试角度给出建议。通过需求分析&#xff0c;不仅可以输出测试点&#xff0c;也可以发现需求中存在的问题。 业务角度和技术角度 测试需求的分析可以从两个不同的角度进行…

介绍5款 世界范围内比较广的 5款 mysql Database Management Tool

介绍5款 世界范围内比较广的 5款 Mysql Database Management Tool 文章目录 介绍5款 世界范围内比较广的 5款 Mysql Database Management Tool前言MySQL Workbench&#xff1a;Navicat Premium&#xff1a;DBeaver Community&#xff1a;HeidiSQL&#xff1a;SQLyog&#xff1a…

如何解决node-sass下载用的还是过期的淘宝源?

下载node-sass发现报错过期的证书 把npm的淘宝源换成最新的https://registry.npmmirror.com后发现还是指向了以前的淘宝源&#xff0c;看到一位博主说&#xff0c;单改npm源不够还要改下载node-sass的源&#xff0c;再次搜索另外一位博主提供了命令npm config ls可以使用它来查…

文件包含漏洞之包含NGINX日志文件(常用)

条件&#xff1a;知道目标服务器的日志文件存贮路径&#xff0c;并且存在文件包含漏洞 首先对目标服务器发送一次含有木马的请求&#xff0c;目的是让目标服务器日志中生成含有木马的日志记录。因为发送过程中&#xff0c;使用了url编码&#xff0c;我们抓包进行更改成能够执行…

图文详解io_uring高性能异步IO架构

说到高性能网络编程&#xff0c;我们第一时间想到的是epoll机制&#xff0c;epoll很长一段时间统治着整个网络编程江湖&#xff0c;然而io_uring的出现&#xff0c;似乎在撼动epoll的统治地位&#xff0c;今天我们来揭开io_uring的神秘面纱。 1.io_uring简介 io_uring是一个L…

竞赛 - 基于机器视觉的图像拼接算法

前言 图像拼接在实际的应用场景很广&#xff0c;比如无人机航拍&#xff0c;遥感图像等等&#xff0c;图像拼接是进一步做图像理解基础步骤&#xff0c;拼接效果的好坏直接影响接下来的工作&#xff0c;所以一个好的图像拼接算法非常重要。 再举一个身边的例子吧&#xff0c;…

Mac 使用 pip install mysqlclient 爆错 error: subprocess-exited-with-error 解决办法

在虚拟环境中安装 mysqlclient 发生报错&#xff1a; pipenv install mysqlclient报错如下&#xff1a; ERROR:pip.subprocessor:Getting requirements to build wheel exited with 1 [ResolutionFailure]: File "/Users/zhangyongxin/.local/share/virtualenvs/movie…

express+mysql+vue,从零搭建一个商城管理系统16--收货地址(全国省市县名称和code列表)

提示&#xff1a;学习express&#xff0c;搭建管理系统 文章目录 前言一、新建config/area.js二、新建models/address.js三、新建dao/address.js四、新建routes/address.js五、添加地址六、查询用户地址列表总结 前言 需求&#xff1a;主要学习express&#xff0c;所以先写serv…

Spring Data访问Elasticsearch----脚本和运行时字段Scripted and runtime fields

Spring Data访问Elasticsearch----脚本和运行时字段Scripted and runtime fields 一、person 实体二、存储库接口三、service类四、脚本化字段Scripted fields五、运行时字段Runtime fields Spring Data Elasticsearch支持脚本(scripted)字段和运行时(runtime)字段。有关此方面…

浅谈大模型“幻觉”问题

大模型的幻觉大概来源于算法对于数据处理的混乱&#xff0c;它不像人类一样可以by the book&#xff0c;它没有一个权威的对照数据源。 什么是大模型幻觉 大模型的幻觉&#xff08;Hallucination&#xff09;是指当人工智能模型生成的内容与提供的源内容不符或没有意义的现象。…

SpringCloud Gateway工作流程

Spring Cloud Gateway的工作流程 具体的流程&#xff1a; 用户发送请求到网关 请求断言&#xff0c;用户请求到达网关后&#xff0c;由Gateway Handler Mapping&#xff08;网关处理器映射&#xff09;进行Predicates&#xff08;断言&#xff09;&#xff0c;看一下哪一个符合…

windows docker

写在前面的废话 最近在学习riscv的软件相关内容&#xff0c;倒是有别人的sg2042机器可以通过ssh使用&#xff0c;但是用起来太不方便了&#xff0c;经常断掉&#xff0c;所以想着在自己的机器上跑一跑riscv的操作系统。最常见的有两种方法吧&#xff0c;第一个就是qemu&#xf…

数据库运行状况和性能监控工具

数据库监控是跟踪组织中数据库的可用性、安全性和性能的过程&#xff0c;它涉及通过跟踪各种关键指标来分析数据库的性能&#xff0c;确保数据库的正常运行并具有深入的可见性&#xff0c;并在出现潜在问题时触发即时警报&#xff0c;以采取主动措施来确保数据库的高可用性。 …

制定工业物联网战略? 成功的5个关键考虑因素

随着越来越多的公司争夺注意力和收入&#xff0c;成功和创造、建设和创新的压力也在增加&#xff0c;这导致了对工业物联网战略的更大需求。 随着越来越多的公司争夺注意力和收入&#xff0c;成功和创造、建设和创新的压力也在增加&#xff0c;这导致了对工业物联网战略的更大需…

Win11专业工作站版系统密钥

Windows 11 专业工作站版是 Windows 11 专业版的加强版本&#xff0c;专为满足高性能工作负载的需求而设计。它在专业版的基础上增加了以下功能&#xff1a; 更高的硬件支持: 支持多达 4 个 CPU 和 6 TB 内存&#xff0c;支持最新的服务器级处理器和图形卡。增强的存储性能: 支…

一招让你的Mac重获新生,CleanMyMac助你轻松清理无用垃圾!

一招让你的Mac重获新生&#xff0c;CleanMyMac助你轻松清理无用垃圾&#xff01; 告别卡顿&#xff0c;让你的Mac跑得更快更稳&#xff01; 在当今这个快节奏的生活中&#xff0c;我们的工作和生活早已离不开电脑。特别是对于Mac用户来说&#xff0c;一台轻巧、快捷、稳定的Mac…

java算法第28天 | 93.复原IP地址 78.子集 90.子集II

93.复原IP地址 思路&#xff1a; 这里startIndex为插入‘.’的位置&#xff0c;使用回溯法遍历所有插入的位置&#xff0c;直接在原始字符串上操作。要注意的是开闭区间的规定&#xff08;这里我规定的是左闭右闭区间&#xff09;。还要明确什么时候能return。 class Solution…