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

异步方法调用详解

文档说明

本文主要针对同类,不同类方法之间的异步调用详解。

本文基于Spring @Async 异步调用四种场景教学文档。

1.所有入口方法 testMain() 均添加 @Transactional 事务;
2.区分:异步逻辑是否和主方法同一事务、是否跟随主方法回滚;
3.核心前置知识点:@Async 基于 AOP 代理生效,同类this调用失效;afterCommit 事务提交后才执行回调逻辑;
4.前置配置:启动类添加 @EnableAsync 开启异步支持。

场景一:A 类 testMain 事务内,异步调用外部 B 类 testB1

1. 主业务类 ClassA

import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; @Service public class ClassA { @Resource private ClassB classB; /** * 主入口方法,开启事务 */ @Transactional public void testMain() { // 1. 主线务数据库操作(和testMain同事务) // 2. 异步调用外部B类方法 classB.testB1(); // 3. 其余业务操作 // 主线程仅将异步任务提交线程池,无需阻塞等待异步逻辑执行完毕,继续向下执行业务代码。 } }

2.外部异步类 ClassB

import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class ClassB { /** * 异步业务方法 * 独立线程、独立事务 */ @Async @Transactional public void testB1() { // 数据库操作、耗时业务逻辑 } }

3.事务回滚说明

若testMain中的业务于第一步的代码发生异常回滚,testB1不会随testMain一起回滚,testB1没执行。

若testMain中的业务于第三步的代码发生了异常回滚,则testB1已经执行了。

testB1 内部报错:testMain事务不受影响,testMain数据正常提交。因为@Async相当于开启了一个全新的线程,两个之间互不影响。

场景二、A 类 testMain 事务内,afterCommit 回调中异步调用外部 B 类 testB1

1. 主业务类 ClassA

import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import javax.annotation.Resource; @Service public class ClassA { @Resource private ClassB classB; @Transactional public void testMain() { // 主线务数据库操作 // 注册事务提交后回调 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { // 主线事务完全提交落库后,才异步执行 classB.testB1(); } }); } }

2.外部异步类 ClassB

import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class ClassB { /** * 异步业务方法 * 独立线程、独立事务 */ @Async @Transactional public void testB1() { // 数据库操作、耗时业务逻辑 } }

3.事务回滚说明

若testMain中的业务代码发生异常回滚,testB1压根不会执行,因为afterCommit 回调仅在主线事务完整提交成功后才执行;主线事务回滚时,回调逻辑完全不执行。

testB1 内部报错:testMain事务不受影响,testMain数据正常提交。

场景三、A 类 testMain 事务内,异步调用本类 3 个方法

每次 getBean 获取代理调用本类方法,直接用this调用会使异步注解失效。

针对多个异步本类方法的调用,建议不用获取getBean的方式调用,频繁通过 getBean 获取代理对象存在重复容器查询开销,多异步方法时不利于统一管控线程池参数。建议使用线程池管理调用。

1. 主业务类ClassA

import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class ClassA implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Transactional public void testMain() { // 1.主线务数据库操作 // 2.每次通过容器获取代理对象,调用本类异步方法 ClassA proxy = applicationContext.getBean(ClassA.class); proxy.testSub1(); proxy.testSub2(); proxy.testSub3(); // 3.其余业务操作 } @Async @Transactional public void testSub1() { // 异步业务1 } @Async @Transactional public void testSub2() { // 异步业务2 } @Async @Transactional public void testSub3() { // 异步业务3 } }

2. 事务回滚说明

若testMain中的业务于第一步的代码发生异常回滚,testSub不会随testMain一起回滚,testSub没执行。

若testMain中的业务于第三步的代码发生了异常回滚,testSub已经执行了。

testB1 内部报错:testMain事务不受影响,testMain数据正常提交。因为@Async相当于开启了一个全新的线程,两个之间互不影响。

场景四、A 类 testMain 事务内,afterCommit 回调中异步调用本类 3 个方法

1. 主业务类ClassA

import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; @Service public class ClassA implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Transactional public void testMain() { // 主线务数据库操作 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void afterCommit() { // 事务提交后,获取代理执行本类异步方法 ClassA proxy = applicationContext.getBean(ClassA.class); proxy.testSub1(); proxy.testSub2(); proxy.testSub3(); } }); } @Async @Transactional public void testSub1() {} @Async @Transactional public void testSub2() {} @Async @Transactional public void testSub3() {} }

2. 事务回滚说明

若testMain中的业务代码发生异常回滚,testSub压根不会执行,因为afterCommit 回调仅在主线事务完整提交成功后才执行;主线事务回滚时,回调逻辑完全不执行。

testSub 内部报错:testMain事务不受影响,testMain数据正常提交。

总结说明

场景执行时机主线回滚后异步是否执行异步报错是否回滚主线
场景 1 直接异步调用外部类主线执行中并行触发可能执行不回滚主线
场景 2 afterCommit 异步外部类主线事务提交后触发不会执行不回滚主线
场景 3 直接异步调用本类 (getBean)主线执行中并行触发可能执行不回滚主线
场景 4 afterCommit 异步调用本类 (getBean)主线事务提交后触发不会执行不回滚主线

使用建议

1.若有数据库操作一类的建议使用场景2

2.针对多个异步本类方法的调用,建议不用获取getBean的方式调用,频繁通过 getBean 获取代理对象存在重复容器查询开销,多异步方法时不利于统一管控线程池参数。建议使用线程池管理调用。

http://www.cnnetsun.cn/news/3097349.html

相关文章:

  • 零食生产线爬坡转弯输送系统(双爬坡机+转弯机)选型指南
  • 透明质酸敷料批发商实力之选:四川昂宇医疗器械有限公司深度解析
  • WinBtrfs完全指南:在Windows系统上无缝访问Linux Btrfs文件系统
  • 九年深耕亚克力,以匠心方寸,承载世界赛事的荣光
  • 【安全月报】| 6 月加密货币领域因安全事件损失约 8173 万美元
  • 深度学习图像数据集构建:从采集到标注的工程化实践
  • 自编码器驱动的图像标注:构建可解释、可演化的标注先验引擎
  • 公证亲属关系需要多少钱?公证亲属关系办理时长?
  • 三、本次入侵需要带来启示的点
  • Web渗透测试“一课一得”——从信息收集到漏洞利用的实战总结
  • 豆包怎么生成 Word 文档?Markdown 转 docx、表格和公式处理思路
  • docker~BuildKit的介绍
  • 锂离子电池保护电路设计:BQ29200与STM32实战解析
  • 计算机毕业设计之基于大数据加护的国产美妆行业发展状况研究
  • AI芯片吃电太猛?横向供电扛不住了,VPD垂直供电来了
  • AI 自动写作覆盖自媒体,四成团队已落地流程
  • 《AJRCCM》(IF: 21.7)|空间单细胞蛋白组揭示EGFR/KRAS突变特异的免疫生态位与NSCLC预后标志物
  • 然后用上面的API测试数据运行下看下效果,发现构建出来的树完全符合我们的预期:
  • Java中String.valueOf(null)的惊天大坑:对比两个数时,日志打印的两数都是null,但Objects.equals()返回false!
  • 2026年想在常州买靠谱二手车?这些门道你不可不知!
  • 5分钟快速上手:终极免费Chrome视频下载插件完整指南
  • 06 — 接口层架构与实现
  • 场外衍生品的详细解读:从产品结构到业务流程,一文看懂核心逻辑
  • KMR221与PIC32MZ的高精度电压监测方案解析
  • 程序员不想只靠死工资增收!盘点 5 类适合技术人深耕的优质副业,闲暇时间额外增加收入
  • JMeter性能测试实战:精准测量QPS、TPS与吞吐量的完整指南
  • 信创系统修复合集①:统信UOS竟然自带系统修复工具
  • PostgreSQL pg_dump工具存在安全漏洞,可导致源数据库服务器的超级用户在客户端执行psql恢复操作时,触发任意代码执行HGVE-2025-E007
  • 多模型 API 网关压测:并发、延迟与计费的三角平衡
  • 构建高效漏洞速查字典:一句话版本通报的设计与实战