详解Spring Boot 异步执行方法

网友投稿 254 2023-02-10


详解Spring Boot 异步执行方法

最近遇到一个需求,就是当服务器接到请求并不需要任务执行完成才返回结果,可以立即返回结果,让任务异步的去执行。开始考虑是直接启一个新的线程去执行任务或者把任务提交到一个线程池去执行,这两种方法都是可以的。但是 Spring 这么强大,肯定有什么更简单的方法,就 google 了一下,还真有呢。就是使用 @Enablhttp://eAsync 和 @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 TkKENcNhreadPoolTaskExecutor();

}

}

指定 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() + "=========");

}

}

这样在异步执行任http://务的时候就使用 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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:解决SpringMVC Controller 接收页面传递的中文参数出现乱码的问题
下一篇:Java五子棋单机版源码分享
相关文章

 发表评论

暂时没有评论,来抢沙发吧~