详解Spring Boot 异步执行方法

 更新时间:2018年03月27日 16:54:16   作者:Simeone_xu  
这篇文章主要介绍了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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 利用Java搭建个简单的Netty通信实例教程

    利用Java搭建个简单的Netty通信实例教程

    这篇文章主要给大家介绍了关于如何利用Java搭建个简单的Netty通信,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-05-05
  • Java线程组操作实例分析

    Java线程组操作实例分析

    这篇文章主要介绍了Java线程组操作,结合实例形式分析了ThreadGroup类创建与使用线程组相关操作技巧,需要的朋友可以参考下
    2019-09-09
  • springboot解决java.lang.ArrayStoreException异常

    springboot解决java.lang.ArrayStoreException异常

    这篇文章介绍了springboot解决java.lang.ArrayStoreException异常的方法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • SpringBoot3集成swagger文档的使用方法

    SpringBoot3集成swagger文档的使用方法

    本文介绍了Swagger的诞生背景、主要功能以及如何在Spring Boot 3中集成Swagger文档,Swagger可以帮助自动生成API文档,实现与代码同步,并提供交互式测试功能,使用方法包括导入依赖、配置文档、使用常见注解以及访问生成的Swagger UI和文档,感兴趣的朋友跟随小编一起看看吧
    2025-01-01
  • Java虚拟机之对象创建过程与类加载机制及双亲委派模型

    Java虚拟机之对象创建过程与类加载机制及双亲委派模型

    这篇文章主要给大家介绍了关于Java虚拟机之对象创建过程与类加载机制及双亲委派模型的相关资料,本文通过示例代码以及图文介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友可以参考下
    2021-11-11
  • JavaWeb开发之使用jQuery与Ajax实现动态联级菜单效果

    JavaWeb开发之使用jQuery与Ajax实现动态联级菜单效果

    这篇文章主要介绍了JavaWeb开发之使用jQuery与Ajax实现动态联级菜单效果的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-10-10
  • JAVA 枚举单例模式及源码分析的实例详解

    JAVA 枚举单例模式及源码分析的实例详解

    这篇文章主要介绍了 JAVA 枚举单例模式及源码分析的实例详解的相关资料,需要的朋友可以参考下
    2017-08-08
  • java去除if...else的七种方法总结

    java去除if...else的七种方法总结

    相信小伙伴一定看过多篇怎么去掉 if...else 的文章,也知道大家都很有心得,知道多种方法来去掉 if...else ,本文为大家整理了7个常用的方法,希望对大家有所帮助
    2023-11-11
  • Java公平锁与非公平锁的核心原理讲解

    Java公平锁与非公平锁的核心原理讲解

    从公平的角度来说,Java 中的锁总共可分为两类:公平锁和非公平锁。但公平锁和非公平锁有哪些区别?核心原理是什么?本文就来和大家详细聊聊
    2022-11-11
  • Java实现序列化与反序列化的简单示例

    Java实现序列化与反序列化的简单示例

    序列化与反序列化是指Java对象与字节序列的相互转换,一般在保存或传输字节序列的时候会用到,下面有两个Java实现序列化与反序列化的简单示例,不过还是先来看看序列和反序列化的具体概念:
    2016-05-05

最新评论