深入了解Spring Boot中@Async注解的8大坑点
文章目录
- 1. 缺少@EnableAsync注解
- 2. 异步方法需独立
- 3. 不同的异步方法间无法相互调用
- 4. 返回值为void的异步方法无法捕获异常
- 5. 外部无法直接调用带有@Async注解的方法
- 6. @Async方法不适用于private方法
- 7. 缺失异步线程池配置
- 8. 异步方法与事务的兼容
- 结语

🎉深入了解Spring Boot中@Async注解的8大坑点
- ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹
- ✨博客主页:IT·陈寒的博客
- 🎈该系列文章专栏:架构设计
- 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习
- 🍹文章作者技术和水平有限,如果文中出现错误,希望大家能指正🙏
- 📜 欢迎大家关注! ❤️
Spring Boot是一个流行的Java开发框架,提供了丰富的功能和便捷的配置,使得开发者可以更专注于业务逻辑。在异步编程方面,Spring Boot提供了@Async
注解,它能够让方法异步执行,提高系统的并发性能。然而,在使用@Async
注解时,有一些潜在的坑需要注意。本文将深入探讨Spring Boot中使用@Async
注解时可能遇到的8大坑点,并提供相应的解决方案。
1. 缺少@EnableAsync注解
在使用@Async
注解之前,必须在Spring Boot应用程序的主配置类上添加@EnableAsync
注解,以启用异步方法的支持。如果忽略了这一步,@Async
注解将不会生效。
@SpringBootApplication
@EnableAsync
public class YourApplication {public static void main(String[] args) {SpringApplication.run(YourApplication.class, args);}
}
2. 异步方法需独立
被@Async
注解修饰的方法不能直接被同一个类中的其他方法调用。因为Spring会在运行时生成一个代理类,调用异步方法时实际上是调用这个代理类的方法。因此,如果在同一个类中直接调用异步方法,@Async
注解将不会生效。
@Service
public class YourService {@Asyncpublic void asyncMethod() {// 异步执行的逻辑}public void callingAsyncMethod() {// 直接调用asyncMethod将无法异步执行asyncMethod();}
}
解决方案是通过注入YourService
的代理对象来调用异步方法。
@Service
public class YourService {@Autowiredprivate YourService self;@Asyncpublic void asyncMethod() {// 异步执行的逻辑}public void callingAsyncMethod() {// 通过代理对象调用异步方法self.asyncMethod();}
}
3. 不同的异步方法间无法相互调用
在同一个类中,一个异步方法调用另一个异步方法,也会出现不会异步执行的问题。这是由于Spring默认使用基于代理的AOP来实现异步方法,代理对象内部的方法调用不会触发AOP拦截。
@Service
public class YourService {@Asyncpublic void asyncMethod1() {// 异步执行的逻辑}@Asyncpublic void asyncMethod2() {// 异步执行的逻辑asyncMethod1(); // 这里调用将不会异步执行}
}
解决方案是通过AopContext.currentProxy()获取当前代理对象,再调用异步方法。
@Service
public class YourService {@Autowiredprivate YourService self;@Asyncpublic void asyncMethod1() {// 异步执行的逻辑}@Asyncpublic void asyncMethod2() {// 异步执行的逻辑self.asyncMethod1(); // 通过代理对象调用将异步执行}
}
4. 返回值为void的异步方法无法捕获异常
如果使用@Async
注解的异步方法的返回值为void
,那么这个方法中抛出的异常将无法被捕获。这是因为在异步方法的调用线程和实际执行异步方法的线程之间无法传递异常。
@Service
public class YourService {@Asyncpublic void asyncMethod() {// 异步执行的逻辑throw new RuntimeException("Async method exception");}
}
解决方案是将返回值设置为Future
,这样就可以在调用get()
方法时捕获到异常。
@Service
public class YourService {@Asyncpublic Future<Void> asyncMethod() {// 异步执行的逻辑throw new RuntimeException("Async method exception");}
}
在调用异步方法时,可以通过Future
的get()
方法捕获到异常。
@Service
public class YourService {@Autowiredprivate YourService self;public void callAsyncMethod() {try {self.asyncMethod().get();} catch (Exception e) {// 捕获异常}}
}
5. 外部无法直接调用带有@Async注解的方法
如果在同一个类中直接调用带有@Async
注解的方法,是无法异步执行的。因为Spring会在运行时生成一个代理类,外部直接调用实际上是调用的原始类的方法,而不是代理类的方法。
@Service
public class YourService {@Asyncpublic void asyncMethod() {// 异步执行的逻辑}
}@Service
public class AnotherService {@Autowiredprivate YourService yourService;public void callAsyncMethod() {// 外部直接调用asyncMethod将无法异步执行yourService.asyncMethod();}
}
解决方案是通过注入YourService
的代理对象来调用异步方法。
@Service
public class YourService {@Autowiredprivate YourService self;@Asyncpublic void asyncMethod() {// 异步执行的逻辑}
}@Service
public class AnotherService {@Autowiredprivate YourService self;public void callAsyncMethod() {// 通过代理对象调用异步方法self.asyncMethod();}
}
6. @Async方法不适用于private方法
@Async
注解只对公有方法有效,因此`private
方法无法异步执行。如果尝试给一个
private方法添加
@Async`注解,将不会产生任何效果。
@Service
public class YourService {@Asyncprivate void asyncMethod() {// 这里的@Async注解将不会生效}
}
解决方案是将要异步执行的逻辑抽取到一个公有方法中,并在私有方法中调用这个公有方法。
@Service
public class YourService {@Asyncpublic void asyncMethod() {doAsyncMethod();}private void doAsyncMethod() {// 异步执行的逻辑}
}
7. 缺失异步线程池配置
在使用@Async
注解时,Spring Boot默认会创建一个线程池来执行异步方法。如果没有进行配置,默认使用的是SimpleAsyncTaskExecutor
,这是一个单线程的执行器,可能会导致性能瓶颈。
为了解决这个问题,可以配置一个合适的线程池。以下是一个示例的配置:
@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.setThreadNamePrefix("Async-");executor.initialize();return executor;}
}
这个配置使用了ThreadPoolTaskExecutor
,并设置了核心线程数、最大线程数、队列容量等参数,根据实际情况进行调整。
8. 异步方法与事务的兼容
在默认情况下,使用@Async
注解的方法与事务是不兼容的。因为在使用事务的方法中调用使用@Async
注解的方法时,事务将无法传播到异步方法中,异步方法将在没有事务的情况下执行。
解决方案是将@Async
注解添加到另外一个类的方法上,通过代理对象来调用异步方法。
@Service
public class YourService {@Autowiredprivate AsyncService asyncService;@Transactionalpublic void transactionalMethod() {// 在事务中调用异步方法asyncService.asyncMethod();}
}@Service
public class AsyncService {@Asyncpublic void asyncMethod() {// 异步执行的逻辑}
}
通过将异步方法移动到另一个类中,可以确保异步方法在新的事务中执行,与外部事务不会产生冲突。
结语
使用@Async
注解能够提高系统的并发性能,但在使用时需要注意一些潜在的问题。通过深入了解Spring Boot中@Async
注解的这8大坑点,并采取相应的解决方案,可以更好地应用异步编程,确保系统的可靠性和性能。希望本文对您理解和使用Spring Boot中的异步注解有所帮助。
🧸结尾 ❤️ 感谢您的支持和鼓励! 😊🙏
📜您可能感兴趣的内容:
- 【Java面试技巧】Java面试八股文 - 掌握面试必备知识(目录篇)
- 【Java学习路线】2023年完整版Java学习路线图
- 【AIGC人工智能】Chat GPT是什么,初学者怎么使用Chat GPT,需要注意些什么
- 【Java实战项目】SpringBoot+SSM实战:打造高效便捷的企业级Java外卖订购系统
- 【数据结构学习】从零起步:学习数据结构的完整路径
相关文章:

深入了解Spring Boot中@Async注解的8大坑点
文章目录 1. 缺少EnableAsync注解2. 异步方法需独立3. 不同的异步方法间无法相互调用4. 返回值为void的异步方法无法捕获异常5. 外部无法直接调用带有Async注解的方法6. Async方法不适用于private方法7. 缺失异步线程池配置8. 异步方法与事务的兼容结语 🎉深入了解S…...

C语言——深入理解指针(3)
目录 1. 字符指针 2. 数组指针 2.1 数组指针变量 2.2 数组指针变量的初始化 3.二维数组传参(本质) 4. 函数指针 4.1 函数指针变量的创建 4.2 函数指针的使用 4.3 typedef 5. 函数指针数组 6. 转移表(函数指针数组的使用ÿ…...

图书管理系统源码,图书管理系统开发,图书借阅系统源码配置和运行图解源码已附加
目录 配置简介和软件条件 数据库附件配置 vs应用程序web.config配置数据库链接字符串 数据库文件脚本代码 配置简介和软件条件 所需要的软件是Vs2017以上数据库是Sqlserver2012以上,如果数据库附件不了可以使用数据库脚本附件数据库脚本会在文章末尾写出来。可以…...

FFmpeg介绍
官方网站:http://www.ffmpeg.org/ 项目组成 libavformat 封装模块,封装了Protocol层和Demuxer、Muxer层,使得协议和格式对于开发者来说是透明的。FFmpeg能否支持一种封装格式的视频的封装与解封装,完全取决于这个库,…...
修改网卡PHY的灯-RK3568
文章目录 前言1.定制PHY的灯2.通过命令修改LED状态3.修改驱动效果前言 前面我们已经移植了网卡到开发板上面,也能够正常的进行通信,但是,我们会发现座子上面的灯并没有全部亮起来,而且这些灯的含义是什么,并没有讲解到,这里,就此问题,展开学习。 PHY 有一个重要的功能…...

11月29日作业
作业: 自己封装一个矩形类(Rect),拥有私有属性:宽度(width)、高度(height), 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show(…...

【从删库到跑路 | MySQL总结篇】表的增删查改(进阶下)
个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】🎈 本专栏旨在分享学习MySQL的一点学习心得,欢迎大家在评论区讨论💌 目录 一、联合…...

【机器学习 | 可视化系列】可视化系列 之 决策树可视化
🤵♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…...
配置阿里云的yum仓库
目录 配置阿里云的yum源 清理官方yum源 下载阿里云的yum源 centos7下载阿里云yum源: 清理yum缓存:yum cleam all 生成自己的yum缓存:yum makecache 使用centos自带的官方yum源下载很慢,那今天来跟大家说说配置阿里云的yum仓…...
Kubernetes之kubeadm日志展示篇—K8S私有云worker节点gluster安装部署
文章目录 一. 服务器信息1.1 环境准备1.2 配置hosts解析记录 二. 安装与部署2.1 配置仓库 (所有节点)2.2 安装服务 (所有节点)2.3 启动服务 (所有节点)2.4 配置资源池 (主节点)2.5 创…...

P3368 【模板】树状数组 2 (区间修改,单点查询)
本题链接:【模板】树状数组 2 - 洛谷 题目: 输入 5 5 1 5 4 2 3 1 2 4 2 2 3 1 1 5 -1 1 3 5 7 2 4 输出 6 10 思路: 根据题意,这里是需要区间添加值,单点查询值。如果区间添加值中暴力去一个个加值,肯定…...

智慧城市运营管理平台解决方案:PPT全文61页,附下载
关键词:智慧城市建设方案,智慧城市解决方案,智慧城市的发展前景和趋势,智慧城市建设内容,智慧城市运营管理平台 一、智慧城市运营平台建设背景 随着城市化进程的加速,城市面临着诸多挑战,如环…...

Vue性能优化方法
一、前言 1.1 为什么需要性能优化 用户体验:优化性能可以提升用户体验,降低加载时间和响应时间,让用户更快地看到页面内容。SEO优化:搜索引擎更喜欢快速响应的网站,优化性能可以提高网站的排名。节约成本࿱…...

关于网站的favicon.ico图标的设置需要注意的几点
01-必须在网页的head标签中放上对icon图标的说明语句: 比如下面这样的语句: <link rel"shortcut icon" href"/favicon.ico">否则,浏览器虽然能读到图标,但是不会把图标显示在标签上。 02-为了和本地开…...

PHP中关于func_get_args()方法
首先呢这个函数出现的是比较早的,大致应该是PHP4出现的, func_get_args — 返回一个包含函数参数列表的数组 说明 func_get_args(): array 获取函数参数列表的数组。 该函数可以配合 func_get_arg() 和 func_num_args() 一起使用,从而使得用户自定义函数可以接…...

EMA训练微调
就是取前几个epoch的weight的平均值,可以缓解微调时的灾难性遗忘(因为新数据引导,模型权重逐渐,偏离训练时学到的数据分布,忘记之前学好的先验知识) class EMA():def __init__(self, model, decay):self.…...
Kafka集群部署详细教程
版本说明 Ubuntu 18.04.6Zookeeper 3.5.9Kafka 2.7.0JDK8 集群配置 操作系统ip域名Zookeeper 端口Kafka 端口Ubuntu 18.04.6192.168.50.131kafka1.com21819092Ubuntu 18.04.6192.168.50.132kafka2.com21819092Ubuntu 18.04.6192.168.50.133kafka3.com21819092 安装 vim, cu…...

交叉编译
1. 交叉开发 交叉编译: 在电脑把程序编写 编译 调试好 再下载到嵌入式产品中运行 编译: gcc 之前编译环境和运行环境是一样的 交叉编译: 编译 把编译代码和运行分开 编译代码在虚拟机中 运行…...
数据结构与算法之递归: LeetCode 46. 全排列 (Typescript版)
全排列 https://leetcode.cn/problems/permutations/ 描述 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,…...
SQL中 JOIN 的两种连接类型:内连接(自然连接、自连接、交叉连接)、外连接(左外连接、右外连接、全外连接)
SQL中 JOIN 的两种连接类型:内连接(自然连接、自连接、交叉连接)、外连接(左外连接、右外连接、全外连接) 1. 自然连接(natural join)(内连接) 学生表 mysql> sele…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...