资讯专栏INFORMATION COLUMN

Spring Boot 异步执行方法

jiekechoo / 3356人阅读

摘要:最近遇到一个需求,就是当服务器接到请求并不需要任务执行完成才返回结果,可以立即返回结果,让任务异步的去执行。指定从上面执行的日志可以猜测到默认使用来异步执行任务的,可以搜索到这个类。

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

正确捕获到了异常。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71008.html

相关文章

  • Spring Boot 2.1.0 已发布,7 个重大更新!

    摘要:距离重磅正式发布已经过去大半年了,而在月底就发布了,我们来看下都更新了什么,每一个技术人都值得关注。性能提升应用程序性能改进性能作为团队持续努力的一部分,性能提升在中取得了一些重大进展。 距离《重磅:Spring Boot 2.0 正式发布!》已经过去大半年了,而 Spring Boot 2.1.0 在 10 月底就发布了,我们来看下 Spring Boot 2.1.0 都更新了什么,...

    Forest10 评论0 收藏0
  • 慕课网_《SpringBoot开发常用技术整合》学习总结

    摘要:时间年月日星期四说明本文部分内容均来自慕课网。哈希表实现命令,将哈希表中的域的值设为实现命令,返回哈希表中给定域的值实现命令,删除哈希表中的一个或多个指定域,不存在的域将被忽略。实现命令,返回哈希表中,所有的域和值。 时间:2018年04月19日星期四说明:本文部分内容均来自慕课网。@慕课网:https://www.imooc.com教学源码:https://github.com/zc...

    chengtao1633 评论0 收藏0
  • 《Java编程方法论:响应式RxJava与代码设计实战》序

    摘要:原文链接编程方法论响应式与代码设计实战序,来自于微信公众号次灵均阁正文内容在一月的架构和设计趋势报告中,响应式编程和函数式仍旧编列在第一季度的早期采纳者中。 原文链接:《Java编程方法论:响应式RxJava与代码设计实战》序,来自于微信公众号:次灵均阁 正文内容 在《2019 一月的InfoQ 架构和设计趋势报告》1中,响应式编程(Reactive Programming)和函数式...

    PAMPANG 评论0 收藏0
  • Spring Boot 2 快速教程:WebFlux 快速入门(二)

    摘要:响应式编程是基于异步和事件驱动的非阻塞程序,只是垂直通过在内启动少量线程扩展,而不是水平通过集群扩展。三特性常用的生产的特性如下响应式编程模型适用性内嵌容器组件还有对日志消息测试及扩展等支持。 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 02:WebFlux 快速入门实践 文章工程: JDK...

    gaara 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<