深入了解Spring Boot中@Async注解的8大坑点

news2025/1/22 9:02:25

文章目录

    • 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 {
    @Async
    public void asyncMethod() {
        // 异步执行的逻辑
    }

    public void callingAsyncMethod() {
        // 直接调用asyncMethod将无法异步执行
        asyncMethod();
    }
}

解决方案是通过注入YourService的代理对象来调用异步方法。

@Service
public class YourService {
    @Autowired
    private YourService self;

    @Async
    public void asyncMethod() {
        // 异步执行的逻辑
    }

    public void callingAsyncMethod() {
        // 通过代理对象调用异步方法
        self.asyncMethod();
    }
}

3. 不同的异步方法间无法相互调用

在同一个类中,一个异步方法调用另一个异步方法,也会出现不会异步执行的问题。这是由于Spring默认使用基于代理的AOP来实现异步方法,代理对象内部的方法调用不会触发AOP拦截。

@Service
public class YourService {
    @Async
    public void asyncMethod1() {
        // 异步执行的逻辑
    }

    @Async
    public void asyncMethod2() {
        // 异步执行的逻辑
        asyncMethod1(); // 这里调用将不会异步执行
    }
}

解决方案是通过AopContext.currentProxy()获取当前代理对象,再调用异步方法。

@Service
public class YourService {
    @Autowired
    private YourService self;

    @Async
    public void asyncMethod1() {
        // 异步执行的逻辑
    }

    @Async
    public void asyncMethod2() {
        // 异步执行的逻辑
        self.asyncMethod1(); // 通过代理对象调用将异步执行
    }
}

4. 返回值为void的异步方法无法捕获异常

如果使用@Async注解的异步方法的返回值为void,那么这个方法中抛出的异常将无法被捕获。这是因为在异步方法的调用线程和实际执行异步方法的线程之间无法传递异常。

@Service
public class YourService {
    @Async
    public void asyncMethod() {
        // 异步执行的逻辑
        throw new RuntimeException("Async method exception");
    }
}

解决方案是将返回值设置为Future,这样就可以在调用get()方法时捕获到异常。

@Service
public class YourService {
    @Async
    public Future<Void> asyncMethod() {
        // 异步执行的逻辑
        throw new RuntimeException("Async method exception");
    }
}

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

@Service
public class YourService {
    @Autowired
    private YourService self;

    public void callAsyncMethod() {
        try {
            self.asyncMethod().get();
        } catch (Exception e) {
            // 捕获异常
        }
    }
}

5. 外部无法直接调用带有@Async注解的方法

如果在同一个类中直接调用带有@Async注解的方法,是无法异步执行的。因为Spring会在运行时生成一个代理类,外部直接调用实际上是调用的原始类的方法,而不是代理类的方法。

@Service
public class YourService {
    @Async
    public void asyncMethod() {
        // 异步执行的逻辑
    }
}

@Service
public class AnotherService {
    @Autowired
    private YourService yourService;

    public void callAsyncMethod() {
        // 外部直接调用asyncMethod将无法异步执行
        yourService.asyncMethod();
    }
}

解决方案是通过注入YourService的代理对象来调用异步方法。

@Service
public class YourService {
    @Autowired
    private YourService self;

    @Async
    public void asyncMethod() {
        // 异步执行的逻辑
    }
}

@Service
public class AnotherService {
    @Autowired
    private YourService self;

    public void callAsyncMethod() {
        // 通过代理对象调用异步方法
        self.asyncMethod();
    }
}

6. @Async方法不适用于private方法

@Async注解只对公有方法有效,因此`private

方法无法异步执行。如果尝试给一个private方法添加@Async`注解,将不会产生任何效果。

@Service
public class YourService {
    @Async
    private void asyncMethod() {
        // 这里的@Async注解将不会生效
    }
}

解决方案是将要异步执行的逻辑抽取到一个公有方法中,并在私有方法中调用这个公有方法。

@Service
public class YourService {
    @Async
    public void asyncMethod() {
        doAsyncMethod();
    }

    private void doAsyncMethod() {
        // 异步执行的逻辑
    }
}

7. 缺失异步线程池配置

在使用@Async注解时,Spring Boot默认会创建一个线程池来执行异步方法。如果没有进行配置,默认使用的是SimpleAsyncTaskExecutor,这是一个单线程的执行器,可能会导致性能瓶颈。

为了解决这个问题,可以配置一个合适的线程池。以下是一个示例的配置:

@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
    @Override
    public 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 {
    @Autowired
    private AsyncService asyncService;

    @Transactional
    public void transactionalMethod() {
        // 在事务中调用异步方法
        asyncService.asyncMethod();
    }
}

@Service
public class AsyncService {
    @Async
    public void asyncMethod() {
        // 异步执行的逻辑
    }
}

通过将异步方法移动到另一个类中,可以确保异步方法在新的事务中执行,与外部事务不会产生冲突。

结语

使用@Async注解能够提高系统的并发性能,但在使用时需要注意一些潜在的问题。通过深入了解Spring Boot中@Async注解的这8大坑点,并采取相应的解决方案,可以更好地应用异步编程,确保系统的可靠性和性能。希望本文对您理解和使用Spring Boot中的异步注解有所帮助。


🧸结尾 ❤️ 感谢您的支持和鼓励! 😊🙏
📜您可能感兴趣的内容:

  • 【Java面试技巧】Java面试八股文 - 掌握面试必备知识(目录篇)
  • 【Java学习路线】2023年完整版Java学习路线图
  • 【AIGC人工智能】Chat GPT是什么,初学者怎么使用Chat GPT,需要注意些什么
  • 【Java实战项目】SpringBoot+SSM实战:打造高效便捷的企业级Java外卖订购系统
  • 【数据结构学习】从零起步:学习数据结构的完整路径

在这里插入图片描述

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

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

相关文章

对于 ` HttpServletResponse ` , ` HttpServletRequest `我们真的学透彻了吗

对于 **HttpServletResponse , HttpServletRequest**我们真的学透彻了吗 问题引入 PostMapping("/importTemplate") public void importTemplate(HttpServletResponse response) {ExcelUtil<SysUser> util new ExcelUtil<SysUser>(SysUser.class);uti…

深入了解Java8新特性-日期时间API之TemporalQuery、TemporalQueries

阅读建议 嗨&#xff0c;伙计&#xff01;刷到这篇文章咱们就是有缘人&#xff0c;在阅读这篇文章前我有一些建议&#xff1a; 本篇文章大概2000多字&#xff0c;预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强&#xff0c;是一篇质量分数较高的技术干货文章&#x…

网络安全 | 使用人工智能阻止网络攻击

全球范围内分布式拒绝服务 (DDoS) 网络攻击急剧增加&#xff0c;这种数字攻击可以通过大量的互联网流量压垮目标服务器&#xff0c;从而使网站瘫痪。这种攻击每年都会发生数百万起&#xff0c;而且数量和规模都在不断增加。大约三分之一的网站宕机是由于 DDoS 攻击所致。 计算…

UVA 108 Maximum Sum

UVA 108 Maximum Sum 题面翻译 给定一个含有正负数的二维数组&#xff0c;找出有最大和的子矩阵。矩阵的和指矩阵中所有元素的和。 一个子矩阵是任意在总矩阵中大小为1x1或更大的邻近子数组&#xff0c;例如在下面的矩阵中: 0 −2 −7 0 9 2 −6 2 −4 1 −4 1 −1 8 0 −…

C++学习寄录(八.继承)

继承的语法&#xff1a;class 子类 : 继承方式 父类 class A : public B; A 类称为子类 或 派生类 B 类称为父类 或 基类 1.基本使用 未使用继承的代码比较冗余重复 #include <iostream> #include <fstream> #include <string> #include <chrono>…

搞定这三个问题 伦敦金止损就没问题

笔者多次强调&#xff0c;做伦敦金交易&#xff0c;重要的是风险控制。而止损是我们风险控制中一个很重要的概念。设定好止损&#xff0c;就是风险控制的好开始。下面我们通过三个问题&#xff0c;来解决止损的问题。 问题一&#xff0c;你的止损位在哪里&#xff1f;要做止损&…

python -- python安装

1、python的诞生和发展&#xff1a; python语言是一种解释型、面向对象型、动态数据类型的高级程序设计语言。 2、python的安装&#xff1a; 1、安装解析器&#xff1a; 在安装的过程中需要注意的是&#xff1a; 在安装pycharm的时候也是同样的道理&#xff0c;需要指定安装…

解决:IDEA的debug模式只有第一次能拦截请求进行debug,后续所有请求全部失效

解决&#xff1a;IDEA的debug模式只有第一次能拦截请求进行debug&#xff0c;后续所有请求全部失效 一问题描述&#xff1a;IDEA的debug模式只有第一次能拦截请求进行debug&#xff0c;后续所有请求全部失效二问题原因&#xff1a;对IDEA的debug功能不熟悉或者理解有偏差三解决…

vs配置64位汇编

vs开发64位程序无法使用内联汇编&#xff0c;需要将汇编放到一个单独文件中编译链接。 步骤如下&#xff1a; 生成汇编代码。以asm.asm为例&#xff0c;以下是模板&#xff1a; ;64位汇编程序模板 (Template) ;声明一个ExitProcess函数 ExitProcess PROTO.data;在这里声明变量…

外汇天眼:外汇市场中的“双向交易”是什么意思?

说到外汇市场&#xff0c;总免不了提到它双向交易的优势&#xff0c;很多新手会对这一点有所疑问&#xff0c;今天我们就帮大家解决这一个疑问。 何谓双向交易&#xff1f; 金融市场上&#xff0c;交易者最常接触到的股票&#xff0c;多属于单向交易。 单向交易的模式便是「先…

如何快速生成项目目录结构树?

经常在网上看到下面这种由一个项目&#xff0c;生成一个结构树&#xff0c;你知道它是怎么生成的吗&#xff1f; 这就是利用本文要介绍的一个工具——Treer&#xff0c;treer就是一款专门用来快速生成目录结构树的命令行工具。 第一步&#xff1a;安装treer 在终端执行全局…

分布式机器学习、联邦学习、多智能体的区别和联系——一文进行详细解释

1 分布式机器学习、联邦学习、多智能体介绍 最近这三个方面的论文都读过&#xff0c;这里写一篇博客归纳一下&#xff0c;以方便搞这几个领域的其他童鞋入门。我们先来介绍以下这三种机器学习范式的基本概念。 1.1 分布式机器学习介绍 分布式机器学习(distributed machine l…

vivado综合分析与收敛技巧3

1、最优化 RAMB 输入逻辑以允许输出寄存器推断 以下 RTL 代码片段可从块 RAM &#xff08; 实际上为 ROM &#xff09; 生成关键路径 &#xff0c; 其中包含多个止于触发器 (FF) 的逻辑层次。 RAMB单元已在无可选输出寄存器 (DOA-0) 的情况下完成推断 &#xff0c; 这给 R…

美颜SDK是什么?美颜SDK对比测评

为了实现实时、高效的美颜效果&#xff0c;开发者们纷纷转向美颜SDK这一技术解决方案。那么&#xff0c;美颜SDK究竟是什么&#xff1f;本文将深入探讨美颜SDK的概念&#xff0c;并通过对比测评不同美颜SDK&#xff0c;为开发者和用户提供更清晰的选择参考。 一、美颜SDK的概念…

高效管理文件方法:根据文件大小智能移动至目标文件夹

在日常的工作中&#xff0c;会遇到大量的文件&#xff0c;从几个KB的小文档到几个GB的大数据文件。如何有效地管理这些文件&#xff0c;以便能够快速找到所需的资料&#xff0c;是一项重要的任务。传统的文件管理方式往往会在大量的文件和文件夹中迷失&#xff0c;而无法快速找…

SAP 第三方销售

SAP 第三方销售 第三方销售是比较常见的业务&#xff0c;&#xff0c;虽然他的一部分属于SD模块&#xff0c;但配置也并不难&#xff0c;一起测试下。 1、流程概述 第三方采购指的是&#xff1a;公司A和客户B签订销售合同&#xff0c;公司在SAP 系统内开销售订单&#xff0c…

temu反洗钱协议在哪里签署

反洗钱是国际社会关注的重要议题之一。为了加强国际合作&#xff0c;各国政府积极参与签署反洗钱协议。TEMU反洗钱协议作为国际间的重要合作框架&#xff0c;其签署地点及其意义备受关注。本文将深入探讨TEMU反洗钱协议的签署地点及其背后的意义。 先给大家推荐一款拼多多/temu…

顶级大厂Quora如何优化数据库性能?

Quora 的流量涉及大量阅读而非写入&#xff0c;一直致力于优化读和数据量而非写。 0 数据库负载的主要部分 读取数据量写入 1 优化读取 1.1 不同类型的读需要不同优化 ① 复杂查询&#xff0c;如连接、聚合等 在查询计数已成为问题的情况下&#xff0c;它们在另一个表中构…

代理模式,dk动态代理,cglib动态代理

目录 一、代理模式1、生活中代理案例2、为什么要使用代理3、代理模式在Java中的应用4、什么是代理模式 二、代理的实现方式1、java中代理图示2、静态代理 三、动态代理1、概述2、JDK动态代理jdk动态代理原理分析 3、Cglib动态代理3.1 基本使用3.2 cglib基本原理 一、代理模式 …

【长文干货】Python可视化教程

文章目录 数据介绍Matplotlib散点图折线图柱形图直方图 Seaborn散点图折线图柱形图直方图 Bokeh散点图折线条形图交互式 Plotly基本组合优化&#xff1a;定制化下拉菜单 总结 数据介绍 在这个小费数据集中&#xff0c;我们记录了20世纪90年代初期餐厅顾客在两个半月内给出的小…