Spring @Async的異常處理

樓主在前面的2篇文章中,分別介紹了Java子線程中通用的異常處理,以及Spring web應用中的異常處理。鏈接如下:

Java子線程中的異常處理(通用)

Spring web引用中的異常處理

今天,要寫的是被Spring @Async註解的方法中的異常處理方法。

 

通常,如果我們要在程序中做一個耗時的操作(例如調用其他外部模塊),一般會通過異步的方式執行。

有這2種方法:

  • 自行生成線程池ThreadPoolExecutor,提交任務執行
  • 更方便地,使用Spring @Async註解,修飾在需要異步執行的方法上

對於第一種方法的異常處理,樓主已經在“Java子線程中的異常處理(通用)”這篇文章中介紹了,也就是提交任務後獲取到Future對象,通過future.get()獲取返回值的時候能夠捕獲到ExcecutionException。

對於Spring @Async註解的方法,如何進行異常處理呢?樓主想到了2種方法。

解決辦法

方法一:配置AsyncUncaughtExceptionHandler(對於無返回值的方法)

通過AsyncConfigurer自定義線程池,以及異常處理。

複製代碼

 1 @Configuration
 2 @EnableAsync
 3 public class SpringAsyncConfiguration implements AsyncConfigurer {
 4     private static final Logger logger = LoggerFactory.getLogger(getClass());

 5     @Bean
 6     @Override
 7     public Executor getAsyncExecutor() {
 8         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 9         executor.setCorePoolSize(8);
10         executor.setMaxPoolSize(16);
11         executor.setQueueCapacity(64);
12         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
13         executor.setThreadNamePrefix("SpringAsyncThread-");
14 
15         return executor;
16     }
17 
18     @Override
19     public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
20         return new SpringAsyncExceptionHandler();
21     }
22 
23     class SpringAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
24         @Override
25         public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
26             logger.error("Exception occurs in async method", throwable.getMessage());
27         }
28     }
29 
30 }

複製代碼

方法二:通過AsyncResult捕獲異常(對於有返回值的方法)

如果異步方法有返回值,那就應當返回AsyncResult類的對象,以便在調用處捕獲異常。

因爲AsyncResult是Future接口的子類,所以也可以通過future.get()獲取返回值的時候捕獲ExcecutionException。

異步方法:

複製代碼

@Service
public class AsyncService {

    @Async
    public AsyncResult<String> asyncMethodWithResult() {
        // do something(可能發生異常)

        return new AsyncResult("hello");
    }

}

複製代碼

調用處捕獲異常:

複製代碼

 1 public class Test {
 2 
 3     private Logger logger = LoggerFactory.getLogger(getClass());
 4 
 5     @Autowired
 6     AsyncService asyncService;
 7 
 8     public void test() {
 9         try {
10             Future future = asyncService.asyncMethodWithResult();
11             future.get();
12         } catch (ExecutionException e) {
13             logger.error("exception occurs", e);
14         } catch (InterruptedException e) {
15             logger.error("exception occurs", e);
16         }
17     }
18 
19 }

複製代碼

 @Async調用中的事務處理機制

    在@Async標註的方法,同時也適用了@Transactional進行了標註;在其調用數據庫操作之時,將無法產生事務管理的控制,原因就在於其是基於異步處理的操作。

     那該如何給這些操作添加事務管理呢?可以將需要事務管理操作的方法放置到異步方法內部,在內部被調用的方法上添加@Transactional.

    例如:  方法A,使用了@Async/@Transactional來標註,但是無法產生事務控制的目的。

          方法B,使用了@Async來標註,  B中調用了C、D,C/D分別使用@Transactional做了標註,則可實現事務控制的目的。

轉自https://www.cnblogs.com/yangfanexp/p/7747225.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章