前言:

最近的时候遇到一个需求,就是当服务器接到请求并不需要任务执行完成才返回结果,可以立即返回结果,让任务异步的去执行。开始考虑是直接启一个新的线程去执行任务或者把任务提交到一个线程池去执行,这两种方法都是可以的。但是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 之异步执行方法的更多相关文章

  1. Spring Boot Async异步执行

    异步调用就是不用等待结果的返回就执行后面的逻辑,同步调用则需要等带结果再执行后面的逻辑. 通常我们使用异步操作都会去创建一个线程执行一段逻辑,然后把这个线程丢到线程池中去执行,代码如下: Execut ...

  2. 使用spring的@Async异步执行方法

    应用场景: 1.某些耗时较长的而用户不需要等待该方法的处理结果 2.某些耗时较长的方法,后面的程序不需要用到这个方法的处理结果时 在spring的配置文件中加入对异步执行的支持 <beans x ...

  3. spring boot启动后执行方法

    @Componentpublic class InitProject implements ApplicationRunner { private static final Logger logger ...

  4. Spring boot 配置异步处理执行器

    示例如下: 1. 新建Maven 项目 async-executor 2.pom.xml <project xmlns="http://maven.apache.org/POM/4.0 ...

  5. 使用Spring Boot和AspectJ实现方法跟踪基础结构

    了解如何使用Spring Boot和AspectJ实现方法跟踪基础结构!最近在优锐课学习收获颇多,记录下来大家一起进步! 在我们的应用程序中,获取方法的堆栈跟踪信息可能会节省很多时间.具有输入输出参数 ...

  6. Spring Boot @Async 异步任务执行

    1.任务执行和调度 Spring用TaskExecutor和TaskScheduler接口提供了异步执行和调度任务的抽象. Spring的TaskExecutor和java.util.concurre ...

  7. Spring Boot 定时+多线程执行

    Spring Boot 定时任务有多种实现方式,我在一个微型项目中通过注解方式执行定时任务. 具体执行的任务,通过多线程方式执行,单线程执行需要1小时的任务,多线程下5分钟就完成了. 执行效率提升10 ...

  8. Spring Boot程序的执行流程

    Spring Boot的执行流程如下图所示:(图片来源于网络) 上图为SpringBoot启动结构图,我们发现启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置 ...

  9. Spring Boot 初始化运行特定方法

    Spring Boot提供了两种 “开机自启动” 的方式,ApplicationRunner和CommandLineRunner 这两种方式的目的是为了满足,在容器启动时like执行某些方法.我们可以 ...

随机推荐

  1. Java描述设计模式(11):观察者模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.观察者模式 1.概念描述 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.观察者模式定义了一种一对多 ...

  2. Java描述设计模式(09):装饰模式

    本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 孙悟空有七十二般变化,他的每一种变化都给他带来一种附加的本领.他变成鱼儿时,就可以到水里游泳:他变成鸟儿时,就可以 ...

  3. jq初始,选择器,事件,内容操作,样式操作

    jq操作页面文档http://jquery.cuishifeng.cn/ jq初始 <!DOCTYPE html> <html> <head> <meta c ...

  4. Vue.js2.0快速入门笔记

    vue.js 解耦视图与数据,可复用的组件,前端路由,状态管理,虚拟DOM. MVVM模式:当View(视图层)变化时,会自动更新ViewModel(视图模型),View与ViewModel之间双向绑 ...

  5. angularjs $http请求网络数据并展示

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. Python完全平方数

    python解题源代码如下: import math """ 简述:一个整数,它加上100和加上268后都是一个完全平方数 提问:请问该数是多少? Python解题思路分 ...

  7. windows下同时安装多个python版本的方法

    根据项目的需要,我的电脑上需要安装的python不止一个版本,比如同时需要python2.7和python3.6: 安装多个python版本 这时需要下载多个python安装包,为了区分不同的pyth ...

  8. Win2003下IIS以FastCGI模式运行PHP

    由于PHP5.3 的改进,原有的IIS 通过isapi 方式解析PHP脚本已经不被支持,PHP从5.3.0 以后的版本开始使用微软的 fastcgi 模式,这是一个更先进的方式,运行速度更快,更稳定. ...

  9. JVM java内存区域的介绍

    jvm虚拟机在运行时需要用到的内存区域.广泛一点就是堆和栈,其实不然,堆和栈只是相对比较笼统的说法,真正区分有如下几个 先上图一: 总的就是 java的内存模型 内存模型又分堆内存(heap)和方法区 ...

  10. deepin/debian 安装docker

    简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会 ...