一文詳解SpringBoot如何優(yōu)雅地實現(xiàn)異步調(diào)用
前言
SpringBoot想必大家都用過,但是大家平時使用發(fā)布的接口大都是同步的,那么你知道如何優(yōu)雅的實現(xiàn)異步呢?
這篇文章就是關(guān)于如何在Spring Boot中實現(xiàn)異步行為的。但首先,讓我們看看同步和異步之間的區(qū)別。
- 同步編程:在同步編程中,任務一次執(zhí)行一個,只有當一個任務完成時,下一個任務才會被解除阻塞。
- 異步編程:在異步編程中,可以同時執(zhí)行多個任務。您可以在上一個任務完成之前轉(zhuǎn)到另一個任務。

在Spring Boot中,我們可以使用@Async注解來實現(xiàn)異步行為。
實現(xiàn)步驟
1.定義一個異步服務接口AsyncService.java
public interface AsyncService {
void asyncMethod() throws InterruptedException;
Future<String> futureMethod() throws InterruptedException;
}
2.實現(xiàn)定義的接口AsyncServiceImpl.java
@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService {
@Async
@Override
public void asyncMethod() throws InterruptedException {
Thread.sleep(3000);
log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName());
}
@Async
@Override
public Future<String> futureMethod() throws InterruptedException {
Thread.sleep(5000);
log.info("Thread: [{}], Calling other service..", Thread.currentThread().getName());
return new AsyncResult<>("task Done");
}
}
AsyncServiceImpl是一個spring管理的bean。- 您的異步方法必須是公共的,而且是被
@Async注解修飾。 - 返回類型被限制為
void或Future。
3.定義一個控制器AsyncController.java
@EnableAsync
@RestController
@Slf4j
public class AsyncController {
@Autowired
AsyncService asyncService;
@GetMapping("/async")
public String asyncCallerMethod() throws InterruptedException {
long start = System.currentTimeMillis();
log.info("call async method, thread name: [{}]", Thread.currentThread().getName());
asyncService.asyncMethod();
String response = "task completes in :" +
(System.currentTimeMillis() - start) + "milliseconds";
return response;
}
@GetMapping("/asyncFuture")
public String asyncFuture() throws InterruptedException, ExecutionException {
long start = System.currentTimeMillis();
log.info("call async method, thread name: [{}]", Thread.currentThread().getName());
Future<String> future = asyncService.futureMethod();
// 阻塞獲取結(jié)果
String taskResult = future.get();
String response = taskResult + "task completes in :" +
(System.currentTimeMillis() - start) + "milliseconds";
return response;
}
}
- 關(guān)鍵點,需要添加啟用異步的注解
@EnableAsync,當然這個注解加在其他地方也ok得。 - 當外部調(diào)用該接口時,
asyncMethod()將由默認任務執(zhí)行程序創(chuàng)建的另一個線程執(zhí)行,主線程不需要等待完成異步方法執(zhí)行。
4.運行一下
現(xiàn)在我們運行一下看看,是不是異步返回的。


可以看到調(diào)用/async接口,最終一步調(diào)用了方法。


調(diào)用/asyncFuture,發(fā)現(xiàn)返回5秒多,難道不是異步的嗎?其實也是異步的,看日志可以看出來,只不過我們返回的是Future,調(diào)用Futrue.get()是阻塞的。
自定義異步任務執(zhí)行器和異常處理
我們現(xiàn)在看看如果異常方法中報錯了會怎么樣?修改異步代碼如下所示,會拋運行時異常:

再次執(zhí)行異步接口,如下所示,會使用默認的線程池和異常處理。

我們也可以自定義異步方法的處理異常和異步任務執(zhí)行器,我們需要配置 AsyncUncaughtExceptionHandler,如下代碼所示:
@Configuration
public class AsynConfiguration extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new
ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(4);
executor.setThreadNamePrefix("asyn-task-thread-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler
getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable ex,
Method method, Object... params) {
System.out.println("Exception: " + ex.getMessage());
System.out.println("Method Name: " + method.getName());
ex.printStackTrace();
}
};
}
}
再次運行,得到的結(jié)果如下:

@Async如何工作的
必須通過使用 @EnableAsync注解注解主應用程序類或任何直接或間接異步方法調(diào)用程序類來啟用異步支持。主要通過代理模式實現(xiàn),默認模式是 Proxy,另一種是 AspectJ。代理模式只允許通過代理攔截調(diào)用。永遠不要從定義它的同一個類調(diào)用異步方法,它不會起作用。
當使用 @Async對方法進行注解時,它會根據(jù)“proxyTargetClass”屬性為該對象創(chuàng)建一個代理。當 spring 執(zhí)行這個方法時,默認情況下它會搜索關(guān)聯(lián)的線程池定義。上下文中唯一的 spring 框架 TaskExecutor bean 或名為“taskExecutor”的 Executor bean。如果這兩者都不可解析,默認會使用spring框架SimpleAsyncTaskExecutor來處理異步方法的執(zhí)行。
總結(jié)
在本文中,我們演示了在 spring boot 中如何使用 @Async 注解和異步方法中的異常處理實現(xiàn)異步行為。我們可以在一個接口中,需要訪問不同的資源,比如異步調(diào)用各個其他服務的接口,可以使用@Async,然后將結(jié)果通過Future的方式阻塞匯總,不失為一個提高性能的好方法。
到此這篇關(guān)于一文詳解SpringBoot如何優(yōu)雅地實現(xiàn)異步調(diào)用的文章就介紹到這了,更多相關(guān)SpringBoot異步調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot 異步調(diào)用的實現(xiàn)方法
- SpringBoot實現(xiàn)定時任務和異步調(diào)用
- SpringBoot開啟異步調(diào)用方法
- SpringBoot異步調(diào)用方法實現(xiàn)場景代碼實例
- springboot實現(xiàn)異步調(diào)用@Async的示例
- 三種SpringBoot中實現(xiàn)異步調(diào)用的方法總結(jié)
- SpringBoot使用@Async注解實現(xiàn)異步調(diào)用
- SpringBoot中的定時任務和異步調(diào)用詳解
- 淺談SpringBoot實現(xiàn)異步調(diào)用的幾種方式
相關(guān)文章
java線程中synchronized和Lock區(qū)別及介紹
這篇文章主要為大家介紹了java線程中synchronized和Lock區(qū)別及介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-06-06
SpringBoot中的ApplicationRunner與CommandLineRunner問題
這篇文章主要介紹了SpringBoot中的ApplicationRunner與CommandLineRunner問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
Java CompletableFuture如何實現(xiàn)超時功能
這篇文章主要為大家介紹了實現(xiàn)超時功能的基本思路以及CompletableFuture(之后簡稱CF)是如何通過代碼實現(xiàn)超時功能的,需要的小伙伴可以了解下2025-01-01

