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

猜你喜欢

转载自blog.csdn.net/sanyaoxu_2/article/details/84556065