时间:2021-05-02
最近遇到一个需求,就是当服务器接到请求并不需要任务执行完成才返回结果,可以立即返回结果,让任务异步的去执行。开始考虑是直接启一个新的线程去执行任务或者把任务提交到一个线程池去执行,这两种方法都是可以的。但是 Spring 这么强大,肯定有什么更简单的方法,就 google 了一下,还真有呢。就是使用 @EnableAsync 和 @Async 这两个注解就 ok 了。
给方法加上 @Async 注解
? 1 2 3 4 5 6 package me.deweixu.aysncdemo.service; public interface AsyncService { void asyncMethod(String arg); } ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 注解
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 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); } }测试
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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") 确实异步执行了,它使用了一个新的线程。
指定 Executor
从上面执行的日志可以猜测到 Spring 默认使用 SimpleAsyncTaskExecutor 来异步执行任务的,可以搜索到这个类。@Async 也可以指定自定义的 Executor。
在启动类中增加自定义的 Executor
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 接口来配置的
? 1 2 3 4 5 6 7 @Configuration public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } }异常捕获
在异步执行的方法中是可能出现异常的,我们可以在任务内部使用 try catch 来处理异常,当任务抛出异常时,Spring 也提供了捕获它的方法。
实现 AsyncUncaughtExceptionHandler 接口
? 1 2 3 4 5 6 7 8 9 10 11 12 13 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 方法
? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Configuration public class SpringAsyncConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { return new ThreadPoolTaskExecutor(); } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new CustomAsyncExceptionHandler(); } }改写 asyncMethod 方法使它抛出异常
? 1 2 3 4 5 6 7 @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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://segmentfault.com/a/1190000013974727
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文介绍了springboot的maven配置依赖详解,分享给大家,具体如下:我们通过引用spring-boot-starter-parent,添加spring
一)spring-boot-starter命名规则自动配置模块命名规则:xxx-spring-boot,如:aspectlog-spring-boot启动器命名
1.什么是spring-boot-devtoolsspring-boot-devtools是spring-boot项目开发时的一个热部署工具,安装了spring
问题描述在spring-boot启动时,希望能执行相应的sql文件来初始化数据库。使用配置文件初始化数据库可以在spring-boot的配置文件applicat
【背景】spring-boot项目,打包成可执行jar,项目内有两个带有main方法的类并且都使用了@SpringBootApplication注解(或者另一种