Spring Boot 之异步执行方法

匿名 (未验证) 提交于 2019-12-02 21:52:03

前言:

最近的时候遇到一个需求,就是当服务器接到请求并不需要任务执行完成才返回结果,可以立即返回结果,让任务异步的去执行。开始考虑是直接启一个新的线程去执行任务或者把任务提交到一个线程池去执行,这两种方法都是可以的。但是Spring 这么强大,肯定有什么更简单的方法,就 google 了一下,还真有呢。就是使用 @EnableAsync 和 @Async 这两个注解就 ok 了。

 

 

 

给方法加上 @Async 注解

package me.deweixu.aysncdemo.service;public interface AsyncService { void asyncMethod(String arg);}
package me.deweixu.aysncdemo.service.ipml;import me.deweixu.aysncdemo.service.AsyncService;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Servicepublic class AsyncServiceImpl implements AsyncService { @Async @Override public void asyncMethod(String arg) { System.out.println("arg:" + arg); System.out.println("=====" + Thread.currentThread().getName() + "========="); }}

@EnableAsync

在启动类或者配置类加上 @EnableAsync 注解

package me.deweixu.aysncdemo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableAsync;@EnableAsync@SpringBootApplicationpublic class AysncDemoApplication { public static void main(String[] args) { SpringApplication.run(AysncDemoApplication.class, args); }}

测试

package me.deweixu.aysncdemo;import me.deweixu.aysncdemo.service.AsyncService;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)@SpringBootTestpublic class AysncDemoApplicationTests { @Autowired AsyncService asyncService; @Test public void testAsync() { System.out.println("=====" + Thread.currentThread().getName() + "========="); asyncService.asyncMethod("Async"); }}
=====main=========2018-03-25 21:30:31.391 INFO 28742 --- [ main] .s.a.AnnotationAsyncExecutionInterceptor : No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' eitherarg:Async=====SimpleAsyncTaskExecutor-1=========

 

从上面的结果看 asyncService.asyncMethod("Async") 确实异步执行了,它使用了一个新的线程。

指定 "Executor"

从上面执行的日志可以猜测到 Spring 默认使用 SimpleAsyncTaskExecutor 来异步执行任务的,可以搜索到这个类。 @Async 也可以指定自定义的 Executor。

在启动类中增加自定义的 Executor

package me.deweixu.aysncdemo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.annotation.Bean;import org.springframework.scheduling.annotation.EnableAsync;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;@EnableAsync@SpringBootApplicationpublic class AysncDemoApplication { public static void main(String[] args) { SpringApplication.run(AysncDemoApplication.class, args); } @Bean(name = "threadPoolTaskExecutor") public Executor threadPoolTaskExecutor() { return new ThreadPoolTaskExecutor(); }}

指定 "Executor"

package me.deweixu.aysncdemo.service.ipml;import me.deweixu.aysncdemo.service.AsyncService;import org.springframework.scheduling.annotation.Async;import org.springframework.stereotype.Service;@Servicepublic class AsyncServiceImpl implements AsyncService { @Async("threadPoolTaskExecutor") @Override public void asyncMethod(String arg) { System.out.println("arg:" + arg); System.out.println("=====" + Thread.currentThread().getName() + "========="); }}

这样在异步执行任务的时候就使用 threadPoolTaskExecutor

设置默认的

Executor

上面提到如果 @Async 不指定 Executor 就默认使用 SimpleAsyncTaskExecutor,其实默认的 Executor 是可以使用 AsyncConfigurer 接口来配置的

@Configurationpublic class SpringAsyncConfig implements AsyncConfigurer {  @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } }

异常捕获

在异步执行的方法中是可能出现异常的,我们可以在任务内部使用 try catch 来处理异常,当任务抛出异常时, Spring 也提供了捕获它的方法。

实现 AsyncUncaughtExceptionHandler 接口

public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {  @Override public void handleUncaughtException( Throwable throwable, Method method, Object... obj) {  System.out.println("Exception message - " + throwable.getMessage()); System.out.println("Method name - " + method.getName()); for (Object param : obj) { System.out.println("Parameter value - " + param); } } }
实现 AsyncConfigurer 接口重写 getAsyncUncaughtExceptionHandler 方法
@Configurationpublic class SpringAsyncConfig implements AsyncConfigurer {  @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); }  @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler(); } }

改写 asyncMethod 方法使它抛出异常

 @Async @Override public void asyncMethod(String arg) { System.out.println("arg:" + arg); System.out.println("=====" + Thread.currentThread().getName() + "========="); throw new NullPointerException(); }

运行结果:

=====main=========arg:Async=====threadPoolTaskExecutor-1=========Exception message - Async NullPointerExceptionMethod name - asyncMethodParameter value - Async

正确捕获到了异常。

我是小架,我们

下篇文章见!

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!