SpringBoot使用@Async注解可能會遇到的8大坑點匯總
正文
1、未啟用異步支持
Spring Boot默認情況下不啟用異步支持,確保在主配置類上添加
@EnableAsync
注解以啟用異步功能。
@SpringBootApplication @EnableAsync public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
2、沒有配置線程池
如果沒有顯式地配置線程池,Spring Boot將使用默認的SimpleAsyncTaskExecutor實現(xiàn)。
在生產(chǎn)環(huán)境,可能導(dǎo)致性能問題。建議使用自定義的線程池配置,推薦ThreadPoolTaskExecutor。
@Configuration @EnableAsync public class AsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); // 設(shè)置核心線程數(shù) executor.setMaxPoolSize(100); // 設(shè)置最大線程數(shù) executor.setQueueCapacity(10); // 設(shè)置隊列容量 executor.setThreadNamePrefix("Async-"); // 設(shè)置線程名前綴 executor.initialize(); return executor; } // 其他配置方法... }
3、異步方法在同一個類調(diào)用
異步方法必須是通過代理機制來觸發(fā)的,因此如果在同一個類中調(diào)用異步方法,它將無法通過代理機制工作。
可以嘗試將異步方法移到另一個Bean中,然后通過依賴注入進行調(diào)用,這也是萬金油用法。
// 你的業(yè)務(wù)服務(wù) @Service public class MyService { @Autowired private AsyncService asyncService; @Async public void asyncMethod() { // 異步方法邏輯... asyncService.asyncMethod(); // 在另一個Bean中調(diào)用異步方法 } } // 你聲明的異步服務(wù),這里面可以是你所有的異步方法,哪里調(diào)用直接注入即可。 @Service public class AsyncService { @Async public void asyncMethod() { // 異步方法邏輯... } }
4、事務(wù)失效問題
@Async方法默認不會繼承父方法的事務(wù)。如果需要事務(wù)支持,請確保異步方法和調(diào)用該方法的方法都被@Transactional注解標(biāo)記。
@Service public class MyService { @Autowired private MyRepository myRepository; @Async @Transactional public void asyncMethod() { // 異步方法邏輯... myRepository.save(entity); } }
5、異常處理
異步方法中拋出的異常不能直接捕獲,因為調(diào)用者將無法獲取到異常。建議使用Future或CompletableFuture來捕獲異步方法的異常并進行處理。
@Service public class MyService { @Async public CompletableFuture<String> asyncMethod() { try { // 異步方法邏輯... return CompletableFuture.completedFuture("Success"); } catch (Exception e) { // 處理異常... return CompletableFuture.failedFuture(e); } } } // 調(diào)用異步方法并處理異常 CompletableFuture<String> future = myService.asyncMethod(); future.exceptionally(ex -> { // 異常處理邏輯... return "Error"; });
6、異步方法無返回結(jié)果
異步方法默認情況下是沒有返回值的,如果需要獲取異步方法的執(zhí)行結(jié)果,依然要使用Future或CompletableFuture,可以將其設(shè)置為返回類型。
@Service public class MyService { @Async public CompletableFuture<String> asyncMethod() { // 異步方法邏輯... return CompletableFuture.completedFuture("Result"); } } // 調(diào)用異步方法并獲取結(jié)果 CompletableFuture<String> future = myService.asyncMethod(); String result = future.get(); // 阻塞等待結(jié)果
當(dāng)然,正常情況下我們不需要返回結(jié)果,而且我也不建議這么干,異步線程本身也最適合處理不需要返回值的一類任務(wù)。
7、循環(huán)調(diào)用問題
當(dāng)在同一個類中調(diào)用異步方法時,注意避免出現(xiàn)無限遞歸的循環(huán)調(diào)用。這可能會導(dǎo)致應(yīng)用程序卡死或內(nèi)存溢出。
@Service public class MyService { @Autowired private MyService myService; // 自身依賴 @Async public void asyncMethod() { // 異步方法邏輯... myService.asyncMethod(); // 會導(dǎo)致無限遞歸調(diào)用 } }
這個坑點一般人不會遇到,但如果某些業(yè)務(wù)場景是關(guān)于樹形結(jié)構(gòu)的遍歷、圖算法等等,還是有幾率出現(xiàn)這種情況的,這個坑點列出來僅供學(xué)習(xí)和了解。
8、異步方法順序問題
異步方法的執(zhí)行是非阻塞的,它們可能以任意順序完成。如果需要按照特定的順序處理結(jié)果,可以使用CompletableFuture的thenApply方法或者使用@Async的order屬性來指定順序。
@Service public class MyService { @Async("threadPoolTaskExecutor") public CompletableFuture<String> asyncMethod1() { // 異步方法1邏輯... return CompletableFuture.completedFuture("Result1"); } @Async("threadPoolTaskExecutor") public CompletableFuture<String> asyncMethod2() { // 異步方法2邏輯... return CompletableFuture.completedFuture("Result2"); } } // 調(diào)用異步方法并處理結(jié)果順序 CompletableFuture<String> future1 = myService.asyncMethod1(); CompletableFuture<String> future2 = future1.thenCompose( result1 -> myService.asyncMethod2()); String finalResult = future2.get(); // 阻塞等待最終結(jié)果
總結(jié)
這里面,我個人認為絕大多數(shù)人會遇到的坑點集中在沒有配置自定義線程池、異步方法在同一個類中調(diào)用、事務(wù)不起作用這幾個問題上。
所以,萬金油的寫法還是專門定義一個AsyncService,將異步方法都寫在里面,需要使用的時候,就在其他類將其注入即可。
以上就是SpringBoot使用@Async注解可能會遇到的8大坑點匯總的詳細內(nèi)容,更多關(guān)于SpringBoot @Async注解坑點的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于Java應(yīng)用日志與Jaeger的trace關(guān)聯(lián)的問題
這篇文章主要介紹了Java應(yīng)用日志如何與Jaeger的trace關(guān)聯(lián),通過jaeger發(fā)現(xiàn)這十次請求中有一次耗時特別長,想定位一下具體原因,感興趣的朋友跟隨小編一起看看吧2022-01-01SpringBoot整合Security權(quán)限控制登錄首頁
這篇文章主要為大家介紹了SpringBoot整合Security權(quán)限控制登錄首頁示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11Java 獲取當(dāng)前時間及實現(xiàn)時間倒計時功能【推薦】
這篇文章主要介紹了Java 獲取當(dāng)前時間及實現(xiàn)時間倒計時功能 ,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-05-05Java實現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例
這篇文章主要介紹了Java實現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例,值得一提的是所謂的雙向冒泡排序并不比普通的冒泡排序效率來得高,注意相應(yīng)的時間復(fù)雜度,需要的朋友可以參考下2016-04-04基于Security實現(xiàn)OIDC單點登錄的詳細流程
本文主要是給大家介紹 OIDC 的核心概念以及如何通過對 Spring Security 的授權(quán)碼模式進行擴展來實現(xiàn) OIDC 的單點登錄。對Security實現(xiàn)OIDC單點登錄的詳細過程感興趣的朋友,一起看看吧2021-09-09