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