mirror of
https://gitee.com/yudaocode/SpringBoot-Labs.git
synced 2026-09-03 05:53:54 +08:00
增加 spring 异步任务的示例
This commit is contained in:
@@ -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) 。
|
||||
|
||||
## 性能测试
|
||||
|
||||
|
||||
30
lab-29/lab-29-async-demo/pom.xml
Normal file
30
lab-29/lab-29-async-demo/pom.xml
Normal 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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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("听说我被异步调用了");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
14
lab-29/lab-29-async-demo/src/main/resources/application.yaml
Normal file
14
lab-29/lab-29-async-demo/src/main/resources/application.yaml
Normal 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 ,根据自己应用来设置
|
||||
@@ -0,0 +1 @@
|
||||
package cn.iocoder.springboot.lab29.asynctask;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
30
lab-29/lab-29-async-two/pom.xml
Normal file
30
lab-29/lab-29-async-two/pom.xml
Normal 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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* 核心封装
|
||||
*/
|
||||
package cn.iocoder.springboot.lab29.asynctask.core;
|
||||
@@ -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("发生了一个可爱的异常");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package cn.iocoder.springboot.lab29.asynctask;
|
||||
@@ -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
20
lab-29/pom.xml
Normal 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>
|
||||
Reference in New Issue
Block a user