From 5fddfb2bedb86a144c60237e90e481320ae4698e Mon Sep 17 00:00:00 2001 From: yidao620 Date: Wed, 28 Feb 2018 11:17:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BB=A3=E7=A0=81=E7=A4=BA?= =?UTF-8?q?=E4=BE=8Bspringboot-async?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- springboot-async/.gitignore | 14 +++ springboot-async/LICENSE | 20 +++++ springboot-async/README.md | 13 +++ springboot-async/pom.xml | 87 +++++++++++++++++++ springboot-async/run.sh | 72 +++++++++++++++ .../java/com/xncoding/pos/Application.java | 12 +++ .../xncoding/pos/async/AsyncException.java | 37 ++++++++ .../pos/async/AsyncExceptionHandler.java | 30 +++++++ .../com/xncoding/pos/async/AsyncTask.java | 46 ++++++++++ .../com/xncoding/pos/config/AsyncConfig.java | 41 +++++++++ .../src/main/resources/application.yml | 39 +++++++++ .../src/main/resources/banner.txt | 23 +++++ .../com/xncoding/pos/ApplicationTests.java | 39 +++++++++ 14 files changed, 474 insertions(+), 1 deletion(-) create mode 100644 springboot-async/.gitignore create mode 100644 springboot-async/LICENSE create mode 100644 springboot-async/README.md create mode 100644 springboot-async/pom.xml create mode 100644 springboot-async/run.sh create mode 100644 springboot-async/src/main/java/com/xncoding/pos/Application.java create mode 100644 springboot-async/src/main/java/com/xncoding/pos/async/AsyncException.java create mode 100644 springboot-async/src/main/java/com/xncoding/pos/async/AsyncExceptionHandler.java create mode 100644 springboot-async/src/main/java/com/xncoding/pos/async/AsyncTask.java create mode 100644 springboot-async/src/main/java/com/xncoding/pos/config/AsyncConfig.java create mode 100644 springboot-async/src/main/resources/application.yml create mode 100644 springboot-async/src/main/resources/banner.txt create mode 100644 springboot-async/src/test/java/com/xncoding/pos/ApplicationTests.java diff --git a/README.md b/README.md index a144f57..260971f 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ app-manage-api | [同时实现了需要认证授权访问的RESTful ## 运行 -每个子项目都可以单独运行,都是打包成jar包后,通过使用内置jetty容器执行,有3种方式运行。 +每个子项目都可以单独运行,都是打包成jar包后,通过使用内置jetty容器执行,有3种方式运行。:point_right: 1. 在IDEA里面直接运行Application.java的main函数。 2. 另一种方式是执行`mvn clean package`命令后传到linux服务器上面,通过命令`java -jar xxx.jar`方式运行 diff --git a/springboot-async/.gitignore b/springboot-async/.gitignore new file mode 100644 index 0000000..1e3c5bb --- /dev/null +++ b/springboot-async/.gitignore @@ -0,0 +1,14 @@ +# 此为注释– 将被Git 忽略 +# /结尾表示是目录,忽略目录和目录下的所有件 +# /开头表示根目录,否则是.gitignore的相对目录 +# !开头表示反选 +.idea/ +target/ +*.iml +*.ipr +*.iws +*.log +.svn/ +.project +rebel.xml +.rebel-remote.xml.* diff --git a/springboot-async/LICENSE b/springboot-async/LICENSE new file mode 100644 index 0000000..83cd47d --- /dev/null +++ b/springboot-async/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2018 Xiong Neng + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/springboot-async/README.md b/springboot-async/README.md new file mode 100644 index 0000000..e88621c --- /dev/null +++ b/springboot-async/README.md @@ -0,0 +1,13 @@ +## 异步线程池 + +演示在SpringBoot中如何使用异步线程池 + +## 测试用例 + +`com.xncoding.pos.ApplicationTests.java` + +## 许可证 + +Copyright (c) 2018 Xiong Neng + +基于 MIT 协议发布: diff --git a/springboot-async/pom.xml b/springboot-async/pom.xml new file mode 100644 index 0000000..89a7c9a --- /dev/null +++ b/springboot-async/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + com.xncoding + springboot-async + 1.0.0-SNAPSHOT + jar + + springboot-async + 异步线程池 + + + org.springframework.boot + spring-boot-starter-parent + 1.5.9.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + org.hamcrest + hamcrest-core + 1.3 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.1 + + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.20 + + true + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + src/main/resources + + + src/main/java + + **/*.xml + + + + + + \ No newline at end of file diff --git a/springboot-async/run.sh b/springboot-async/run.sh new file mode 100644 index 0000000..955efb1 --- /dev/null +++ b/springboot-async/run.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# 项目自动更新脚本 +# 先clone相应的分支下来: +# git clone ssh://git@120.24.173.142:7999/xxx.git +# 远程调试启动: +# nohup java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 & + +function start { + profile="$1" + echo "启动环境profile=${profile}" + jarfile=$(ls target/*.jar) + if [[ "$?" == "0" ]]; then + stop $profile $jarfile + fi + branch=$(git branch |awk '{print $2}') + git pull origin ${branch} + echo "更新完代码开始重新打包" + mvn clean && mvn clean && mvn package -DskipTests=true + if [[ "$?" != "0" ]]; then + echo "编译出错,退出!" + exit 1 + fi + echo "nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 &" + nohup java -Xms512m -Xmx1024m -jar -Dspring.profiles.active=${profile} ${jarfile} >/dev/null 2>&1 & + echo "启动应用中,请查看日志文件..." +} + +function stop { + profile="$1" + jarfile="$2" + ps aux | grep "${jarfile}" | grep "spring.profiles.active=${profile}" | grep -v grep > /dev/null + if [[ "$?" == "0" ]]; then + echo "该应用还在跑,我先停了它" + pid=$(ps aux | grep "${jarfile}" | grep "spring.profiles.active=${profile}" | grep -v grep |awk '{print $2}') + if [[ "$pid" != "" ]]; then + kill -9 $pid + fi + echo "停止应用成功..." + fi +} + +if [[ "$1" == "start" ]]; then + if [[ "$#" < 2 ]]; then + echo "请输入正确参数:./epay.sh start {profile}" + exit 1 + fi + profile="$2" + if [[ "$profile" != "dev" && "$profile" != "test" && "$profile" != "show" && "$profile" != "production" ]]; then + echo "参数错误,请输入正确的profile参数,使用方法:" + echo "./epay.sh start {profile} ==> 启动应用,{profile}取值:dev|test|show|production" + exit 1 + fi + start "${profile}" +elif [[ "$1" == "stop" ]]; then + if [[ "$#" < 2 ]]; then + echo "请输入正确参数:./epay.sh stop {profile}" + exit 1 + fi + profile="$2" + if [[ "$profile" != "dev" && "$profile" != "test" && "$profile" != "show" && "$profile" != "production" ]]; then + echo "参数错误,请输入正确的profile参数,使用方法:" + echo "./epay.sh stop {profile} ==> 停止应用,{profile}取值:dev|test|show|production" + exit 1 + fi + jarfile=$(ls target/*.jar) + stop $profile $jarfile +else + echo "参数错误,使用方法:{}参数是必填的,[]参数可选" + echo "./epay.sh start {profile} ==> 启动应用,{profile}取值:dev|test|show|production" + echo "./epay.sh stop {profile} ==> 停止应用,{profile}取值:dev|test|show|production" + exit 1 +fi diff --git a/springboot-async/src/main/java/com/xncoding/pos/Application.java b/springboot-async/src/main/java/com/xncoding/pos/Application.java new file mode 100644 index 0000000..adc4c48 --- /dev/null +++ b/springboot-async/src/main/java/com/xncoding/pos/Application.java @@ -0,0 +1,12 @@ +package com.xncoding.pos; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/springboot-async/src/main/java/com/xncoding/pos/async/AsyncException.java b/springboot-async/src/main/java/com/xncoding/pos/async/AsyncException.java new file mode 100644 index 0000000..9706371 --- /dev/null +++ b/springboot-async/src/main/java/com/xncoding/pos/async/AsyncException.java @@ -0,0 +1,37 @@ +package com.xncoding.pos.async; + +/** + * 异步方法异常 + * + * @author XiongNeng + * @version 1.0 + * @since 2018/1/25 + */ +public class AsyncException extends RuntimeException { + public AsyncException() { + super(); + } + + public AsyncException(String msg) { + super(msg); + } + + public AsyncException(int code, String msg) { + super(msg); + this.code = code; + } + + /** + * 错误代码 + */ + private int code; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + +} diff --git a/springboot-async/src/main/java/com/xncoding/pos/async/AsyncExceptionHandler.java b/springboot-async/src/main/java/com/xncoding/pos/async/AsyncExceptionHandler.java new file mode 100644 index 0000000..755852f --- /dev/null +++ b/springboot-async/src/main/java/com/xncoding/pos/async/AsyncExceptionHandler.java @@ -0,0 +1,30 @@ +package com.xncoding.pos.async; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; + +import java.lang.reflect.Method; +import java.util.Arrays; + +/** + * AsyncExceptionHandler + * + * @author XiongNeng + * @version 1.0 + * @since 2018/1/25 + */ +public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler { + private static final Logger log = LoggerFactory.getLogger(AsyncExceptionHandler.class); + @Override + public void handleUncaughtException(Throwable ex, Method method, Object... params) { + log.error("Async method has uncaught exception, params:{}" + Arrays.toString(params)); + + if (ex instanceof AsyncException) { + AsyncException asyncException = (AsyncException) ex; + log.error("asyncException:" + asyncException.getMessage()); + } + + log.error("Exception :", ex); + } +} diff --git a/springboot-async/src/main/java/com/xncoding/pos/async/AsyncTask.java b/springboot-async/src/main/java/com/xncoding/pos/async/AsyncTask.java new file mode 100644 index 0000000..2b89971 --- /dev/null +++ b/springboot-async/src/main/java/com/xncoding/pos/async/AsyncTask.java @@ -0,0 +1,46 @@ +package com.xncoding.pos.async; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.AsyncResult; +import org.springframework.stereotype.Component; + +import java.util.concurrent.Future; + +/** + * AsyncDemo + * + * @author XiongNeng + * @version 1.0 + * @since 2018/1/25 + */ +@Component +public class AsyncTask { + private static final Logger logger = LoggerFactory.getLogger(AsyncTask.class); + + @Async + public void dealNoReturnTask() { + logger.info("返回值为void的异步调用开始" + Thread.currentThread().getName()); + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + logger.info("返回值为void的异步调用结束" + Thread.currentThread().getName()); + } + + @Async + public Future dealHaveReturnTask(int i) { + logger.info("asyncInvokeReturnFuture, parementer=" + i); + Future future; + try { + Thread.sleep(1000 * i); + future = new AsyncResult("success:" + i); + } catch (InterruptedException e) { + future = new AsyncResult("error"); + } + return future; + } + +} diff --git a/springboot-async/src/main/java/com/xncoding/pos/config/AsyncConfig.java b/springboot-async/src/main/java/com/xncoding/pos/config/AsyncConfig.java new file mode 100644 index 0000000..3d671dd --- /dev/null +++ b/springboot-async/src/main/java/com/xncoding/pos/config/AsyncConfig.java @@ -0,0 +1,41 @@ +package com.xncoding.pos.config; + +import com.xncoding.pos.async.AsyncExceptionHandler; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.concurrent.Executor; + +/** + * AsyncConfig + * + * @author XiongNeng + * @version 1.0 + * @since 2018/1/25 + */ +@Configuration +@EnableAsync +public class AsyncConfig implements AsyncConfigurer { + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(10); + executor.setMaxPoolSize(100); + executor.setQueueCapacity(100); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60 * 10); + executor.setThreadNamePrefix("AsyncThread-"); + executor.initialize(); //如果不初始化,导致找到不到执行器 + return executor; + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return new AsyncExceptionHandler(); + } +} diff --git a/springboot-async/src/main/resources/application.yml b/springboot-async/src/main/resources/application.yml new file mode 100644 index 0000000..90acc9c --- /dev/null +++ b/springboot-async/src/main/resources/application.yml @@ -0,0 +1,39 @@ +########################################################## +################## 所有profile共有的配置 ################# +########################################################## + +################### spring配置 ################### +spring: + profiles: + active: dev + +--- + +##################################################################### +######################## 开发环境profile ########################## +##################################################################### +spring: + profiles: dev + +logging: + level: + ROOT: INFO + com: + xncoding: DEBUG + file: E:/logs/app.log + +--- + +##################################################################### +######################## 测试环境profile ########################## +##################################################################### + +spring: + profiles: test + +logging: + level: + ROOT: INFO + com: + xncoding: DEBUG + file: /var/logs/app.log diff --git a/springboot-async/src/main/resources/banner.txt b/springboot-async/src/main/resources/banner.txt new file mode 100644 index 0000000..859b78f --- /dev/null +++ b/springboot-async/src/main/resources/banner.txt @@ -0,0 +1,23 @@ + + _____ _______ _____ _____ + /\ \ /::\ \ /\ \ /\ \ + /::\____\ /::::\ \ /::\____\ /::\ \ + /:::/ / /::::::\ \ /:::/ / /::::\ \ + /:::/ / /::::::::\ \ /:::/ / /::::::\ \ + /:::/ / /:::/~~\:::\ \ /:::/ / /:::/\:::\ \ + /:::/ / /:::/ \:::\ \ /:::/____/ /:::/__\:::\ \ + /:::/ / /:::/ / \:::\ \ |::| | /::::\ \:::\ \ + /:::/ / /:::/____/ \:::\____\ |::| | _____ /::::::\ \:::\ \ + /:::/ / |:::| | |:::| | |::| | /\ \ /:::/\:::\ \:::\ \ +/:::/____/ |:::|____| |:::| | |::| | /::\____\/:::/__\:::\ \:::\____\ +\:::\ \ \:::\ \ /:::/ / |::| | /:::/ /\:::\ \:::\ \::/ / + \:::\ \ \:::\ \ /:::/ / |::| | /:::/ / \:::\ \:::\ \/____/ + \:::\ \ \:::\ /:::/ / |::|____|/:::/ / \:::\ \:::\ \ + \:::\ \ \:::\__/:::/ / |:::::::::::/ / \:::\ \:::\____\ + \:::\ \ \::::::::/ / \::::::::::/____/ \:::\ \::/ / + \:::\ \ \::::::/ / ~~~~~~~~~~ \:::\ \/____/ + \:::\ \ \::::/ / \:::\ \ + \:::\____\ \::/____/ \:::\____\ + \::/ / ~~ \::/ / + \/____/ \/____/ + diff --git a/springboot-async/src/test/java/com/xncoding/pos/ApplicationTests.java b/springboot-async/src/test/java/com/xncoding/pos/ApplicationTests.java new file mode 100644 index 0000000..0eade3b --- /dev/null +++ b/springboot-async/src/test/java/com/xncoding/pos/ApplicationTests.java @@ -0,0 +1,39 @@ +package com.xncoding.pos; + +import com.xncoding.pos.async.AsyncTask; +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 java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +/** + * 测试异步任务 + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class ApplicationTests { + private static final Logger log = LoggerFactory.getLogger(ApplicationTests.class); + @Autowired + private AsyncTask asyncTask; + + @Test + public void testAsync() throws InterruptedException, ExecutionException { + asyncTask.dealNoReturnTask(); + + Future f = asyncTask.dealHaveReturnTask(5); + + log.info("主线程执行finished"); + + log.info(f.get()); + assertThat(f.get(), is("success:" + 5)); + } +}