当前位置: 首页 > news >正文

深入了解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");}
}

在调用异步方法时,可以通过Futureget()方法捕获到异常。

@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. 异步方法与事务的兼容结语 &#x1f389;深入了解S…...

C语言——深入理解指针(3)

目录 1. 字符指针 2. 数组指针 2.1 数组指针变量 2.2 数组指针变量的初始化 3.二维数组传参&#xff08;本质&#xff09; 4. 函数指针 4.1 函数指针变量的创建 4.2 函数指针的使用 4.3 typedef 5. 函数指针数组 6. 转移表&#xff08;函数指针数组的使用&#xff…...

图书管理系统源码,图书管理系统开发,图书借阅系统源码配置和运行图解源码已附加

目录 配置简介和软件条件 数据库附件配置 vs应用程序web.config配置数据库链接字符串 数据库文件脚本代码 配置简介和软件条件 所需要的软件是Vs2017以上数据库是Sqlserver2012以上&#xff0c;如果数据库附件不了可以使用数据库脚本附件数据库脚本会在文章末尾写出来。可以…...

FFmpeg介绍

官方网站&#xff1a;http://www.ffmpeg.org/ 项目组成 libavformat 封装模块&#xff0c;封装了Protocol层和Demuxer、Muxer层&#xff0c;使得协议和格式对于开发者来说是透明的。FFmpeg能否支持一种封装格式的视频的封装与解封装&#xff0c;完全取决于这个库&#xff0c…...

修改网卡PHY的灯-RK3568

文章目录 前言1.定制PHY的灯2.通过命令修改LED状态3.修改驱动效果前言 前面我们已经移植了网卡到开发板上面,也能够正常的进行通信,但是,我们会发现座子上面的灯并没有全部亮起来,而且这些灯的含义是什么,并没有讲解到,这里,就此问题,展开学习。 PHY 有一个重要的功能…...

11月29日作业

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

【从删库到跑路 | MySQL总结篇】表的增删查改(进阶下)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】&#x1f388; 本专栏旨在分享学习MySQL的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、联合…...

【机器学习 | 可视化系列】可视化系列 之 决策树可视化

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…...

配置阿里云的yum仓库

目录 配置阿里云的yum源 清理官方yum源 下载阿里云的yum源 centos7下载阿里云yum源&#xff1a; 清理yum缓存&#xff1a;yum cleam all 生成自己的yum缓存&#xff1a;yum makecache 使用centos自带的官方yum源下载很慢&#xff0c;那今天来跟大家说说配置阿里云的yum仓…...

Kubernetes之kubeadm日志展示篇—K8S私有云worker节点gluster安装部署

文章目录 一. 服务器信息1.1 环境准备1.2 配置hosts解析记录 二. 安装与部署2.1 配置仓库 &#xff08;所有节点&#xff09;2.2 安装服务 &#xff08;所有节点&#xff09;2.3 启动服务 &#xff08;所有节点&#xff09;2.4 配置资源池 &#xff08;主节点&#xff09;2.5 创…...

P3368 【模板】树状数组 2 (区间修改,单点查询)

本题链接&#xff1a;【模板】树状数组 2 - 洛谷 题目&#xff1a; 输入 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 思路&#xff1a; 根据题意&#xff0c;这里是需要区间添加值&#xff0c;单点查询值。如果区间添加值中暴力去一个个加值&#xff0c;肯定…...

智慧城市运营管理平台解决方案:PPT全文61页,附下载

关键词&#xff1a;智慧城市建设方案&#xff0c;智慧城市解决方案&#xff0c;智慧城市的发展前景和趋势&#xff0c;智慧城市建设内容&#xff0c;智慧城市运营管理平台 一、智慧城市运营平台建设背景 随着城市化进程的加速&#xff0c;城市面临着诸多挑战&#xff0c;如环…...

Vue性能优化方法

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

关于网站的favicon.ico图标的设置需要注意的几点

01-必须在网页的head标签中放上对icon图标的说明语句&#xff1a; 比如下面这样的语句&#xff1a; <link rel"shortcut icon" href"/favicon.ico">否则&#xff0c;浏览器虽然能读到图标&#xff0c;但是不会把图标显示在标签上。 02-为了和本地开…...

PHP中关于func_get_args()方法

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

EMA训练微调

就是取前几个epoch的weight的平均值&#xff0c;可以缓解微调时的灾难性遗忘&#xff08;因为新数据引导&#xff0c;模型权重逐渐&#xff0c;偏离训练时学到的数据分布&#xff0c;忘记之前学好的先验知识&#xff09; 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. 交叉开发 交叉编译&#xff1a; 在电脑把程序编写 编译 调试好 再下载到嵌入式产品中运行 编译&#xff1a; gcc 之前编译环境和运行环境是一样的 交叉编译&#xff1a; 编译 把编译代码和运行分开 编译代码在虚拟机中 运行…...

数据结构与算法之递归: LeetCode 46. 全排列 (Typescript版)

全排列 https://leetcode.cn/problems/permutations/ 描述 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,…...

SQL中 JOIN 的两种连接类型:内连接(自然连接、自连接、交叉连接)、外连接(左外连接、右外连接、全外连接)

SQL中 JOIN 的两种连接类型&#xff1a;内连接&#xff08;自然连接、自连接、交叉连接&#xff09;、外连接&#xff08;左外连接、右外连接、全外连接&#xff09; 1. 自然连接&#xff08;natural join&#xff09;&#xff08;内连接&#xff09; 学生表 mysql> sele…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...