From 0eeb93fd2fd7480afd81ecbb267a18728ee2f56f Mon Sep 17 00:00:00 2001
From: YunaiV <>
Date: Fri, 29 Nov 2019 20:00:43 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20spring=20=E5=BC=82?=
=?UTF-8?q?=E6=AD=A5=E4=BB=BB=E5=8A=A1=E7=9A=84=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 2 +-
lab-29/lab-29-async-demo/pom.xml | 30 +++++
.../lab29/asynctask/Application.java | 15 +++
.../springboot/lab29/asynctask/Demo.java | 23 ++++
.../lab29/asynctask/service/DemoService.java | 100 ++++++++++++++++
.../src/main/resources/application.yaml | 14 +++
.../lab29/asynctask/package-info.java | 1 +
.../asynctask/service/DemoServiceTest.java | 108 ++++++++++++++++++
lab-29/lab-29-async-two/pom.xml | 30 +++++
.../lab29/asynctask/Application.java | 15 +++
.../lab29/asynctask/config/AsyncConfig.java | 22 ++++
.../async/GlobalAsyncExceptionHandler.java | 21 ++++
.../lab29/asynctask/core/package-info.java | 4 +
.../lab29/asynctask/service/DemoService.java | 18 +++
.../lab29/asynctask/package-info.java | 1 +
.../asynctask/service/DemoServiceTest.java | 26 +++++
lab-29/pom.xml | 20 ++++
pom.xml | 1 +
18 files changed, 450 insertions(+), 1 deletion(-)
create mode 100644 lab-29/lab-29-async-demo/pom.xml
create mode 100644 lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/Application.java
create mode 100644 lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/Demo.java
create mode 100644 lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/service/DemoService.java
create mode 100644 lab-29/lab-29-async-demo/src/main/resources/application.yaml
create mode 100644 lab-29/lab-29-async-demo/src/test/java/cn/iocoder/springboot/lab29/asynctask/package-info.java
create mode 100644 lab-29/lab-29-async-demo/src/test/java/cn/iocoder/springboot/lab29/asynctask/service/DemoServiceTest.java
create mode 100644 lab-29/lab-29-async-two/pom.xml
create mode 100644 lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/Application.java
create mode 100644 lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/config/AsyncConfig.java
create mode 100644 lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/core/async/GlobalAsyncExceptionHandler.java
create mode 100644 lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/core/package-info.java
create mode 100644 lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/service/DemoService.java
create mode 100644 lab-29/lab-29-async-two/src/test/java/cn/iocoder/springboot/lab29/asynctask/package-info.java
create mode 100644 lab-29/lab-29-async-two/src/test/java/cn/iocoder/springboot/lab29/asynctask/service/DemoServiceTest.java
create mode 100644 lab-29/pom.xml
diff --git a/README.md b/README.md
index c552876a..60b334da 100644
--- a/README.md
+++ b/README.md
@@ -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) 。
## 性能测试
diff --git a/lab-29/lab-29-async-demo/pom.xml b/lab-29/lab-29-async-demo/pom.xml
new file mode 100644
index 00000000..5acbae23
--- /dev/null
+++ b/lab-29/lab-29-async-demo/pom.xml
@@ -0,0 +1,30 @@
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.1.RELEASE
+
+
+ 4.0.0
+
+ lab-29-async-demo
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
diff --git a/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/Application.java b/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/Application.java
new file mode 100644
index 00000000..e78ac696
--- /dev/null
+++ b/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/Application.java
@@ -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);
+ }
+
+}
diff --git a/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/Demo.java b/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/Demo.java
new file mode 100644
index 00000000..8f0cf6eb
--- /dev/null
+++ b/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/Demo.java
@@ -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("听说我被异步调用了");
+ }
+
+ });
+ }
+
+}
diff --git a/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/service/DemoService.java b/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/service/DemoService.java
new file mode 100644
index 00000000..3c10206d
--- /dev/null
+++ b/lab-29/lab-29-async-demo/src/main/java/cn/iocoder/springboot/lab29/asynctask/service/DemoService.java
@@ -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 execute01Result = execute01AsyncWithFuture();
+// Future 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 execute01AsyncWithFuture() {
+ return AsyncResult.forValue(this.execute01());
+ }
+
+ @Async
+ public Future execute02AsyncWithFuture() {
+ return AsyncResult.forValue(this.execute02());
+ }
+
+ @Async
+ public ListenableFuture 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);
+ }
+ }
+
+}
diff --git a/lab-29/lab-29-async-demo/src/main/resources/application.yaml b/lab-29/lab-29-async-demo/src/main/resources/application.yaml
new file mode 100644
index 00000000..3dfdc84e
--- /dev/null
+++ b/lab-29/lab-29-async-demo/src/main/resources/application.yaml
@@ -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 ,根据自己应用来设置
diff --git a/lab-29/lab-29-async-demo/src/test/java/cn/iocoder/springboot/lab29/asynctask/package-info.java b/lab-29/lab-29-async-demo/src/test/java/cn/iocoder/springboot/lab29/asynctask/package-info.java
new file mode 100644
index 00000000..80dbd94b
--- /dev/null
+++ b/lab-29/lab-29-async-demo/src/test/java/cn/iocoder/springboot/lab29/asynctask/package-info.java
@@ -0,0 +1 @@
+package cn.iocoder.springboot.lab29.asynctask;
diff --git a/lab-29/lab-29-async-demo/src/test/java/cn/iocoder/springboot/lab29/asynctask/service/DemoServiceTest.java b/lab-29/lab-29-async-demo/src/test/java/cn/iocoder/springboot/lab29/asynctask/service/DemoServiceTest.java
new file mode 100644
index 00000000..98d0ff22
--- /dev/null
+++ b/lab-29/lab-29-async-demo/src/test/java/cn/iocoder/springboot/lab29/asynctask/service/DemoServiceTest.java
@@ -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 execute01Result = demoService.execute01AsyncWithFuture();
+ Future 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 execute01Result = demoService.execute01AsyncWithListenableFuture();
+ logger.info("[task04][execute01Result 的类型是:({})]",execute01Result.getClass().getSimpleName());
+ execute01Result.addCallback(new SuccessCallback() { // 增加成功的回调
+
+ @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() { // 增加成功和失败的统一回调
+
+ @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);
+ }
+
+
+}
diff --git a/lab-29/lab-29-async-two/pom.xml b/lab-29/lab-29-async-two/pom.xml
new file mode 100644
index 00000000..72d2043c
--- /dev/null
+++ b/lab-29/lab-29-async-two/pom.xml
@@ -0,0 +1,30 @@
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.1.RELEASE
+
+
+ 4.0.0
+
+ lab-29-async-two
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
diff --git a/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/Application.java b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/Application.java
new file mode 100644
index 00000000..e78ac696
--- /dev/null
+++ b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/Application.java
@@ -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);
+ }
+
+}
diff --git a/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/config/AsyncConfig.java b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/config/AsyncConfig.java
new file mode 100644
index 00000000..ac7bca56
--- /dev/null
+++ b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/config/AsyncConfig.java
@@ -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;
+ }
+
+}
diff --git a/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/core/async/GlobalAsyncExceptionHandler.java b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/core/async/GlobalAsyncExceptionHandler.java
new file mode 100644
index 00000000..5ab7ceed
--- /dev/null
+++ b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/core/async/GlobalAsyncExceptionHandler.java
@@ -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);
+ }
+
+}
diff --git a/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/core/package-info.java b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/core/package-info.java
new file mode 100644
index 00000000..7c5abab3
--- /dev/null
+++ b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/core/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * 核心封装
+ */
+package cn.iocoder.springboot.lab29.asynctask.core;
diff --git a/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/service/DemoService.java b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/service/DemoService.java
new file mode 100644
index 00000000..0e6a6602
--- /dev/null
+++ b/lab-29/lab-29-async-two/src/main/java/cn/iocoder/springboot/lab29/asynctask/service/DemoService.java
@@ -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("发生了一个可爱的异常");
+ }
+
+}
diff --git a/lab-29/lab-29-async-two/src/test/java/cn/iocoder/springboot/lab29/asynctask/package-info.java b/lab-29/lab-29-async-two/src/test/java/cn/iocoder/springboot/lab29/asynctask/package-info.java
new file mode 100644
index 00000000..80dbd94b
--- /dev/null
+++ b/lab-29/lab-29-async-two/src/test/java/cn/iocoder/springboot/lab29/asynctask/package-info.java
@@ -0,0 +1 @@
+package cn.iocoder.springboot.lab29.asynctask;
diff --git a/lab-29/lab-29-async-two/src/test/java/cn/iocoder/springboot/lab29/asynctask/service/DemoServiceTest.java b/lab-29/lab-29-async-two/src/test/java/cn/iocoder/springboot/lab29/asynctask/service/DemoServiceTest.java
new file mode 100644
index 00000000..c202cfd3
--- /dev/null
+++ b/lab-29/lab-29-async-two/src/test/java/cn/iocoder/springboot/lab29/asynctask/service/DemoServiceTest.java
@@ -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);
+ }
+
+}
diff --git a/lab-29/pom.xml b/lab-29/pom.xml
new file mode 100644
index 00000000..5e1974c0
--- /dev/null
+++ b/lab-29/pom.xml
@@ -0,0 +1,20 @@
+
+
+
+ labs-parent
+ cn.iocoder.springboot.labs
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ lab-29
+ pom
+
+ lab-29-async-demo
+ lab-29-async-two
+
+
+
+
diff --git a/pom.xml b/pom.xml
index 14e475ac..4238e6d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,6 +37,7 @@
lab-26
lab-27
lab-28
+ lab-29