最近遇到一个需求,就是当服务器接到请求并不须要任务执行完成才返回结果,能够当即返回结果,让任务异步的去执行。开始考虑是直接启一个新的线程去执行任务或者把任务提交到一个线程池去执行,这两种方法都是能够的。可是Spring
这么强大,确定有什么更简单的方法,就@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; @Service public class AsyncServiceImpl implements AsyncService { @Async @Override public void asyncMethod(String arg) { System.out.println("arg:" + arg); System.out.println("=====" + Thread.currentThread().getName() + "========="); } }
@EnableAsync
在启动类或者配置类加上 @EnableAsync
注解java
package me.deweixu.aysncdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; @EnableAsync @SpringBootApplication public 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) @SpringBootTest public 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' either arg:Async =====SimpleAsyncTaskExecutor-1=========
从上面的结果看 asyncService.asyncMethod("Async")
确实异步执行了,它使用了一个新的线程。spring
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 @SpringBootApplication public 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; @Service public 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
接口来配置的async
@Configuration public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } }
在异步执行的方法中是可能出现异常的,咱们能够在任务内部使用 try catch
来处理异常,当任务抛出异常
时,Spring
也提供了捕获它的方法。ide
实现 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
方法google
@Configuration public 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 NullPointerException Method name - asyncMethod Parameter value - Async
正确捕获到了异常。