springboot異步@Async的使用及失效場景介紹
引言
在 java 中很多業(yè)務(wù)涉及到異步線程,比如在業(yè)務(wù)流處理時(shí),需要發(fā)短信發(fā)郵件通知用戶,或者需要上傳一些文件資源到其他服務(wù)器這種耗時(shí)的操作。
這種比較耗時(shí)的操作如果都在主線程里處理會阻塞整理流程,而且我們也不需要等待處理結(jié)果之后再進(jìn)行下一步操作,這時(shí)候就可以使用異步線程進(jìn)行處理,這樣主線程不會因?yàn)檫@些耗時(shí)的操作而阻塞,保證主線程的流程可以正常進(jìn)行。
一、@Async 使用位置
- 在方法上使用該@Async注解,表明該方法是一個(gè)異步任務(wù)
- 在類上面使用該@Async注解,表明該類中的所有方法都是異步任務(wù)
二、@Async 使用
在 Springboot 中使用 @Async:
- @Async 注解在使用時(shí),如果不指定線程池的名稱,則使用默認(rèn)的線程池,Spring默認(rèn)的線程池為
SimpleAsyncTaskExecutor。 - 方法上一旦標(biāo)記了這個(gè) @Async 注解,當(dāng)其它線程調(diào)用這個(gè)方法時(shí),就會開啟一個(gè)新的子線程去異步處理該業(yè)務(wù)邏輯。
- 啟動類中增加
@EnableAsync注解
代碼示例:
本文不做新配置,全部使用默認(rèn)的線程池及配置。
(1)創(chuàng)建 AsyncService 寫異步方法
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncService {
@Async
public void Async() throws InterruptedException {
Thread.sleep(10000);
System.out.println("程序睡眠結(jié)束");
}
(2)編寫業(yè)務(wù)層 AsyncTestService
package com.ruoyi.system.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncTestService {
@Autowired
private AsyncService asyncService;
public String testSync() throws InterruptedException {
System.out.println("開始進(jìn)入方法");
System.out.println("進(jìn)行時(shí)");
System.out.println("正在進(jìn)行時(shí)");
asyncService.Async();
return "成功";
}
}
(3)編寫接口 AsyncTestController
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "/async/lost")
public class AsyncTestController {
@Autowired
private AsyncTestService asyncTestService;
@RequestMapping(value = "/test", method = {RequestMethod.POST})
public String testAsync() throws InterruptedException {
asyncTestService.testSync();
System.out.println("調(diào)用Controller控制器結(jié)束");
return "成功";
}
}
postman 測試:
從下圖測試結(jié)果可知,打印語句 “調(diào)用Controller控制器結(jié)束” 在 “程序睡眠結(jié)束” 之前執(zhí)行,異步實(shí)現(xiàn)成功,沒有影響到主線程的任務(wù)。

三、注解 @Async 失效的情況
(1)調(diào)用同一個(gè)類中的異步方法(內(nèi)部調(diào)用)
從上面的 @Async 使用我們看到,添加注解的異步方法在一個(gè)單獨(dú)的類 AsyncService 中,然后注入到 AsyncTestService 中進(jìn)行調(diào)用。如果異步方法和調(diào)用的方法在同一個(gè)類中,還會正常進(jìn)行異步調(diào)用嗎?
AsyncTestService 代碼如下:
@Service
public class AsyncTestService {
public String testSync() throws InterruptedException {
System.out.println("開始進(jìn)入方法");
System.out.println("進(jìn)行時(shí)");
System.out.println("正在進(jìn)行時(shí)");
Async();
return "成功";
}
@Async
public void Async() throws InterruptedException {
Thread.sleep(10000);
System.out.println("程序睡眠結(jié)束");
}
}
postman 測試:

如上圖所示,打印語句 “調(diào)用Controller控制器結(jié)束” 在 “程序睡眠結(jié)束” 之后執(zhí)行,說明異步并沒有生效,程序還是走了主線程。
這是因?yàn)?nbsp;@Async注解是通過aop代理實(shí)現(xiàn)的,需要通過JDK動態(tài)代理或者cglib,生成代理對象。異步的功能,是在代理對象中增加的,我們必須調(diào)用代理對象的 testSync() 方法才行。而在類中直接進(jìn)行方法的內(nèi)部調(diào)用,在 testSync() 方法中調(diào)用Async()方法,調(diào)用的是該類原對象的Async方法,相當(dāng)于調(diào)用了this.Async()方法,而并非AsyncTestService 代理類的 Async() 方法。 因此,像這種內(nèi)部方法調(diào)用,@Async注解的異步功能會失效。
要想在同一個(gè)類中調(diào)用異步方法,需要使用 ApplicationContext 獲得到該類。
AsyncTestService 代碼如下:
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class AsyncTestService {
@Autowired
private ApplicationContext applicationContext;
public String testSync() throws InterruptedException {
AsyncTestService asyncBean = applicationContext.getBean(AsyncTestService.class);
System.out.println("當(dāng)前對象是否是代理對象:" + AopUtils.isAopProxy(asyncBean));
System.out.println("是否是cglib代理對象:" + AopUtils.isCglibProxy(asyncBean));
System.out.println("是否是jdk代理對象:" + AopUtils.isJdkDynamicProxy(asyncBean));
System.out.println(asyncBean == this);
asyncBean.Async();
return "成功";
}
@Async
public void Async() throws InterruptedException {
Thread.sleep(10000);
System.out.println("程序睡眠結(jié)束");
}
}
postman 測試:
打印控制器語句在前,異步實(shí)現(xiàn)成功。

(2)未使用 @EnableAsync 注解
在 Springboot 中要開啟@Async注解異步的功能,需要在項(xiàng)目的啟動類,或者配置類上,使用@EnableAsync注解。
@EnableAsync注解相當(dāng)于一個(gè)開關(guān),控制是否開啟@Async注解異步的功能,默認(rèn)是關(guān)閉的。
@EnableAsync
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
(3)注解@Async的方法不是public方法
異步的方法必須是 public修飾的,否則 aop 代理異常,異步失效。
(4)返回值錯誤
注解 @Async 的返回值只能為 void 或 Future。
(5)方法用static修飾了
使用@Async注解聲明的方法,必須是能被重寫的,很顯然static修飾的方法,是類的靜態(tài)方法,是不允許被重寫的。
因此這種情況下,@Async注解的異步功能會失效。
(6)類中需要使用@Autowired或@Resource等注解自動注入,不能自己手動new對象
(7)方法用final修飾
(8)業(yè)務(wù)類沒加@Service注解
到此這篇關(guān)于springboot異步@Async的使用及失效場景介紹的文章就介紹到這了,更多相關(guān)springboot異步@Async內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解java中this.getClass()和super.getClass()的實(shí)例
這篇文章主要介紹了詳解java中this.getClass()和super.getClass()的實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-08-08
Spring4.0 MVC請求json數(shù)據(jù)報(bào)406錯誤的解決方法
這篇文章主要為大家詳細(xì)介紹了Spring4.0 MVC請求json數(shù)據(jù)報(bào)406錯誤的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
springBoot?之spring.factories擴(kuò)展機(jī)制示例解析
這篇文章主要為大家介紹了springBoot?之spring.factories擴(kuò)展機(jī)制示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Java利用cors實(shí)現(xiàn)跨域請求實(shí)例
本篇文章主要介紹了Java利用cors實(shí)現(xiàn)跨域請求實(shí)例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05
SpringBoot多環(huán)境下集成logback的配置指南
Logback是由log4j創(chuàng)始人設(shè)計(jì)的又一個(gè)開源日志組件,可用于項(xiàng)目日志功能,下面小編就來和大家詳細(xì)介紹一下SpringBoot如何在多環(huán)境下集成logback吧2026-02-02
SpringMVC中使用bean來接收form表單提交的參數(shù)時(shí)的注意點(diǎn)
本篇文章主要介紹了SpringMVC中使用bean來接收form表單提交的參數(shù)時(shí)的注意點(diǎn),具有很好的參考價(jià)值。下面跟著小編一起來看下吧2017-05-05
解決Mybatis-Plus中分頁插件Page中total=0的問題
在使用Mybatis-Plus進(jìn)行分頁查詢時(shí),如果遇到`total=0`的情況,即使查詢到了數(shù)據(jù),也無法正確分頁,這通常是由于依賴版本問題導(dǎo)致的,對于低版本,需要手動配置分頁攔截器;對于高版本,可能需要添加特定的依賴配置來解決這個(gè)問題2025-11-11

