增加 spring 异步任务的示例

This commit is contained in:
YunaiV
2019-11-29 20:00:43 +08:00
parent a9e7672d60
commit 0eeb93fd2f
18 changed files with 450 additions and 1 deletions

View File

@@ -31,7 +31,7 @@
## 定时任务与异步任务
* [《芋道 Spring Boot 定时任务入门》](http://www.iocoder.cn/Spring-Boot/Job/?github) 对应 [lab-20](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-28) 。
* [《芋道 Spring Boot 定时任务入门》](http://www.iocoder.cn/Spring-Boot/Job/?github) 对应 [lab-28](https://github.com/YunaiV/SpringBoot-Labs/tree/master/lab-28) 。
## 性能测试

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-29-async-demo</artifactId>
<dependencies>
<!-- 引入 Spring Boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 方便等会写单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,15 @@
package cn.iocoder.springboot.lab29.asynctask;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync // 开启 @Async 的支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.springboot.lab29.asynctask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo {
public static void main(String[] args) {
// 创建线程池。这里只是临时测试,不要扣艿艿遵守阿里 Java 开发规范YEAH
ExecutorService executor = Executors.newFixedThreadPool(10);
// 提交任务到线程池中执行。
executor.submit(new Runnable() {
@Override
public void run() {
System.out.println("听说我被异步调用了");
}
});
}
}

View File

@@ -0,0 +1,100 @@
package cn.iocoder.springboot.lab29.asynctask.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.Future;
@Service
public class DemoService {
private Logger logger = LoggerFactory.getLogger(getClass());
// public void task01() {
// long now = System.currentTimeMillis();
// logger.info("[task01][开始执行]");
//
// execute01();
// execute02();
//
// logger.info("[task01][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
// }
//
// public void task02() {
// long now = System.currentTimeMillis();
// logger.info("[task02][开始执行]");
//
// execute01Async();
// execute02Async();
//
// logger.info("[task02][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
// }
//
// public void task03() throws ExecutionException, InterruptedException {
// long now = System.currentTimeMillis();
// logger.info("[task03][开始执行]");
//
// // 执行任务
// Future<Integer> execute01Result = execute01AsyncWithFuture();
// Future<Integer> execute02Result = execute02AsyncWithFuture();
// // 阻塞等待结果
// execute01Result.get();
// execute02Result.get();
//
// logger.info("[task03][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
// }
@Async
public Integer execute01Async() {
return this.execute01();
}
@Async
public Integer execute02Async() {
return this.execute02();
}
@Async
public Future<Integer> execute01AsyncWithFuture() {
return AsyncResult.forValue(this.execute01());
}
@Async
public Future<Integer> execute02AsyncWithFuture() {
return AsyncResult.forValue(this.execute02());
}
@Async
public ListenableFuture<Integer> execute01AsyncWithListenableFuture() {
try {
return AsyncResult.forValue(this.execute02());
} catch (Throwable ex) {
return AsyncResult.forExecutionException(ex);
}
}
public Integer execute01() {
logger.info("[execute01]");
sleep(10);
return 1;
}
public Integer execute02() {
logger.info("[execute02]");
sleep(5);
return 2;
}
private static void sleep(int seconds) {
try {
Thread.sleep(seconds * 1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,14 @@
spring:
task:
# Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
execution:
thread-name-prefix: task- # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
pool: # 线程池相关
core-size: 8 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
keep-alive: 60 # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
shutdown:
await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置

View File

@@ -0,0 +1 @@
package cn.iocoder.springboot.lab29.asynctask;

View File

@@ -0,0 +1,108 @@
package cn.iocoder.springboot.lab29.asynctask.service;
import cn.iocoder.springboot.lab29.asynctask.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.concurrent.FailureCallback;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.util.concurrent.SuccessCallback;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class DemoServiceTest {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private DemoService demoService;
@Test
public void task01() {
long now = System.currentTimeMillis();
logger.info("[task01][开始执行]");
demoService.execute01();
demoService.execute02();
logger.info("[task01][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
}
@Test
public void task02() {
long now = System.currentTimeMillis();
logger.info("[task02][开始执行]");
demoService.execute01Async();
demoService.execute02Async();
logger.info("[task02][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
}
@Test
public void task03() throws ExecutionException, InterruptedException {
long now = System.currentTimeMillis();
logger.info("[task03][开始执行]");
// 执行任务
Future<Integer> execute01Result = demoService.execute01AsyncWithFuture();
Future<Integer> execute02Result = demoService.execute02AsyncWithFuture();
// 阻塞等待结果
execute01Result.get();
execute02Result.get();
logger.info("[task03][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
}
@Test
public void task04() throws ExecutionException, InterruptedException {
long now = System.currentTimeMillis();
logger.info("[task04][开始执行]");
// 执行任务
ListenableFuture<Integer> execute01Result = demoService.execute01AsyncWithListenableFuture();
logger.info("[task04][execute01Result 的类型是:({})]",execute01Result.getClass().getSimpleName());
execute01Result.addCallback(new SuccessCallback<Integer>() { // 增加成功的回调
@Override
public void onSuccess(Integer result) {
logger.info("[onSuccess][result: {}]", result);
}
}, new FailureCallback() { // 增加失败的回调
@Override
public void onFailure(Throwable ex) {
logger.info("[onFailure][发生异常]", ex);
}
});
execute01Result.addCallback(new ListenableFutureCallback<Integer>() { // 增加成功和失败的统一回调
@Override
public void onSuccess(Integer result) {
logger.info("[onSuccess][result: {}]", result);
}
@Override
public void onFailure(Throwable ex) {
logger.info("[onFailure][发生异常]", ex);
}
});
// 阻塞等待结果
execute01Result.get();
logger.info("[task04][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-29-async-two</artifactId>
<dependencies>
<!-- 引入 Spring Boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 方便等会写单元测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,15 @@
package cn.iocoder.springboot.lab29.asynctask;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync // 开启 @Async 的支持
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,22 @@
package cn.iocoder.springboot.lab29.asynctask.config;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import java.util.concurrent.Executor;
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return null;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}

View File

@@ -0,0 +1,21 @@
package cn.iocoder.springboot.lab29.asynctask.core.async;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Component
public class GlobalAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
logger.error("[handleUncaughtException][method({}) params({}) 发生异常]",
method, params, ex);
}
}

View File

@@ -0,0 +1,4 @@
/**
* 核心封装
*/
package cn.iocoder.springboot.lab29.asynctask.core;

View File

@@ -0,0 +1,18 @@
package cn.iocoder.springboot.lab29.asynctask.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class DemoService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Async
public Integer exception(Integer a, Integer b) {
throw new RuntimeException("发生了一个可爱的异常");
}
}

View File

@@ -0,0 +1 @@
package cn.iocoder.springboot.lab29.asynctask;

View File

@@ -0,0 +1,26 @@
package cn.iocoder.springboot.lab29.asynctask.service;
import cn.iocoder.springboot.lab29.asynctask.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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(classes = Application.class)
public class DemoServiceTest {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private DemoService demoService;
@Test
public void testException() {
demoService.exception(1, 2);
}
}

20
lab-29/pom.xml Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labs-parent</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>lab-29</artifactId>
<packaging>pom</packaging>
<modules>
<module>lab-29-async-demo</module>
<module>lab-29-async-two</module>
</modules>
</project>

View File

@@ -37,6 +37,7 @@
<module>lab-26</module>
<module>lab-27</module>
<module>lab-28</module>
<module>lab-29</module>
</modules>