Spring Boot 之异步执行方法
前言:
最近的时候遇到一个需求,就是当服务器接到请求并不需要任务执行完成才返回结果,可以立即返回结果,让任务异步的去执行。开始考虑是直接启一个新的线程去执行任务或者把任务提交到一个线程池去执行,这两种方法都是可以的。但是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;
@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 注解
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") 确实异步执行了,它使用了一个新的线程。
指定 "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 接口来配置的
@Configuration
public 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 方法
@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
正确捕获到了异常。
我是小架,我们
下篇文章见!
Spring Boot 之异步执行方法的更多相关文章
- Spring Boot Async异步执行
异步调用就是不用等待结果的返回就执行后面的逻辑,同步调用则需要等带结果再执行后面的逻辑. 通常我们使用异步操作都会去创建一个线程执行一段逻辑,然后把这个线程丢到线程池中去执行,代码如下: Execut ...
- 使用spring的@Async异步执行方法
应用场景: 1.某些耗时较长的而用户不需要等待该方法的处理结果 2.某些耗时较长的方法,后面的程序不需要用到这个方法的处理结果时 在spring的配置文件中加入对异步执行的支持 <beans x ...
- spring boot启动后执行方法
@Componentpublic class InitProject implements ApplicationRunner { private static final Logger logger ...
- Spring boot 配置异步处理执行器
示例如下: 1. 新建Maven 项目 async-executor 2.pom.xml <project xmlns="http://maven.apache.org/POM/4.0 ...
- 使用Spring Boot和AspectJ实现方法跟踪基础结构
了解如何使用Spring Boot和AspectJ实现方法跟踪基础结构!最近在优锐课学习收获颇多,记录下来大家一起进步! 在我们的应用程序中,获取方法的堆栈跟踪信息可能会节省很多时间.具有输入输出参数 ...
- Spring Boot @Async 异步任务执行
1.任务执行和调度 Spring用TaskExecutor和TaskScheduler接口提供了异步执行和调度任务的抽象. Spring的TaskExecutor和java.util.concurre ...
- Spring Boot 定时+多线程执行
Spring Boot 定时任务有多种实现方式,我在一个微型项目中通过注解方式执行定时任务. 具体执行的任务,通过多线程方式执行,单线程执行需要1小时的任务,多线程下5分钟就完成了. 执行效率提升10 ...
- Spring Boot程序的执行流程
Spring Boot的执行流程如下图所示:(图片来源于网络) 上图为SpringBoot启动结构图,我们发现启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置 ...
- Spring Boot 初始化运行特定方法
Spring Boot提供了两种 “开机自启动” 的方式,ApplicationRunner和CommandLineRunner 这两种方式的目的是为了满足,在容器启动时like执行某些方法.我们可以 ...
随机推荐
- Linux下离线安装python项目的依赖包
第一步新建一个site-packages文件夹,把python项目有需要的依赖包名称导出到site-packages下的requirements.txt中 $ pip3 freeze > req ...
- Github新项目Dress(好耶是女装)
面向可爱的蓝孩子 (/ω\) 的 git 学习实践项目,包含了600多位蓝孩子的女装照,访问前做好心理准备. 每个人都可以成为这个项目的参与者 访问地址:https://github.com/kome ...
- IO流与装饰者模式
java使用IO流来处理不同设备之间数据的交互;所有的IO操作实际上都是对 Stream 的操作 从功能上划分: 输入流: 当数据从源进入的编写的程序时,称它为输入流; 输出流: 从程序输出回另一个源 ...
- Java中Atomic类的使用分析
1:为什么会出现Atomic类 在多线程或者并发环境中,我们常常会遇到这种情况 int i=0; i++ 稍有经验的同学都知道这种写法是线程不安全的.为了达到线程安全的目的,我们通常会用synchro ...
- Selenium(十八):unittest单元测试框架(四) HTML测试报告
1. HTML测试报告 对测试人员来而言,测试的产出很难衡量.换句话说,测试人员的价值比较难以量化和评估,相信这一点对软件测试人员来说深有体会.我们花费了很多时间与精力所做的自动化测试也是如此.所以, ...
- JPA的entityManager的find方法与getReference方法的区别
场景 JPA入门简介与搭建HelloWorld(附代码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/103473937 ...
- 网络协议 2 - IP 地址和 MAC 地址
了解完网络协议,我们会发现,网络通信的五层模型里,有两个很重要的概念:IP 地址和 MAC 地址. 那么 IP 地址是怎么来的,又是怎么没的?MAC 地址与 IP 地址又有什么区别? 这回答上面问题前 ...
- python中函数
函数特点:一次定义,多次调用 函数阶段:1.定义阶段 2.调用阶段定义阶段的参数叫形参 调用阶段的参数叫实参 例: def test(name,age): print('my name is %s,m ...
- 安装HomeBrew 失败的解决方案(Error: Fetching /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core failed!)
在安装HomeBrew(或者安装成功 执行相关指令)时遇到错误提示: Error: Failure while executing: git clone https://github.com/Home ...
- bay——RAC 表空间时数据文件误放置到本地文件系统-介质恢复.txt
RAC添加新表空间时数据文件误放置到本地文件系统的修正 于是我想11G 也兼容这些操作的方法,但是11G的新特性有一点就是可以直接支持ASM文件系统直接可以和本地文件系统进行文件的拷贝了,也就是有三种 ...