0.
0.1. 疑问
本次重点探讨 Spring Boot 应用的打包和发布。
1. 创建项目(ToyApp)
为了演示需要,基于 Spring Boot 创建一个 WEB 项目 ToyApp。
稍微注意一点:本次引入了一个三方依赖包(idgenerator-spring-boot-starter 是自定义的一个序列号生成器 starter)。
准备好环境,下面一起瞅瞅引入了三方依赖的 Spring Boot 该如何打包?
2. 编译打包
采用 IDEA 集成的 Maven 环境来对 Spring Boot 项目编译打包,可谓是超级 easy。
此时,通过反编译工具来瞅瞅编译打包成功之后的 ToyApp-0.0.1-SNAPSHOT.jar 里面的东西是否缺失,尤其是引入的三方依赖 jar 包。
通过反编译,发现引入的三方依赖 jar 包,没有打进去,咋回事儿?
由于 scope 为 system 的包 maven 默认是不打包进去的,所以解决方案就很简单:只需在 pom.xml 中指定一下 includeSystemScope 就可以。
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <includeSystemScope>true</includeSystemScope> </configuration> </plugin> </plugins></build>
再次编译打包,然后对打成的 jar 包反编译观察一二。
至此,Spring Boot 项目打包就完成了,如果经历过传统的项目开发,相对传统的打包方式,你会知道着实简单不少。
3. 应用发布
3.1 一行命令的演化
运行 Spring Boot 打包之后的 jar 方式也简单,只需一行命令就行。
java -jar /Users/caicai/ToyApp-0.0.1-SNAPSHOT.jar
执行效果:
此时,服务是启动了,但是不能关闭这个窗口,一旦关闭服务就停止了,不得不考虑后台运行,并且还想看日志,所以这一行命令演变成了这个鸟样。
java -jar /Users/caicai/ToyApp-0.0.1-SNAPSHOT.jar > ToyApp.out &
执行启动时,效果如下,然后就可以轻松看日志输出了。
如果项目组中你既是研发又充当运维的角色,到这基本就完事儿了,因为相信通过熟练操作,会形成肌肉反应,你肯定能记住这一行命令。
不过,若是分工明确,生产权限隔离的话,一般都是运维同事来操作发布,所以还得想办法让运维同事省力,不得不考虑脚本化。
3.2 两个脚本
每个项目组的风格不同,而我习惯采取如下目录结构进行管理。
.├── bin(脚本存放目录)│ ├── start.sh│ └── stop.sh├── lib(jar包存放目录)│ └── ToyApp-0.0.1-SNAPSHOT.jar└── logs(日志目录) ├── toyapp.gc.log └── toyapp.out
首先创建项目目录例如 toyapp,然后分别创建 bin、lib、logs 目录;把 ToyApp-0.0.1-SNAPSHOT.jar 拷贝至 lib 目录下;bin 目录主要存放脚本。
在 bin 目录下,创建 start.sh,应用启动脚本。
#!/bin/bash
#配置 Java 环境变量export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_251.jdk/Contents/Homeexport PATH=$JAVA_HOME/bin:$PATH#定义应用名App_Name=toyapp#定义应用所在目录App_Path=/Users/caicai/${App_Name}#定义可执行文件的路径JAR_PATH=${App_Path}/lib/ToyApp-0.0.1-SNAPSHOT.jar#jvm启动参数JAVA_OPTS="-Duser.timezone=GMT+8 -server -Xms4096m -Xmx4096m -XX:MaxMetaspaceSize=256m -Xloggc:${App_Path}/logs/${App_Name}.gc.log -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=5 -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime"#启动JAVA进程函数CURRENT_COUNT=`ps -ef|grep java |grep ${App_Name} |grep -vc grep`if [ $CURRENT_COUNT -eq 0 ]then Log_Name=$(echo ${App_Name}|awk -F"-" '{ print $NF }') nohup java -Dfunc_type=${App_Name} $JAVA_OPTS -Dfile.encoding=utf-8 -jar $JAR_PATH > ${App_Path}/logs/${Log_Name}.out 2>&1 & PROCESS_ID=`ps -ef | grep "${App_Name}" |grep -v grep | awk '{ print $2 }'` echo "\033[44;37m ☺☺☺☺☺启动应用 ${App_Name} 成功,进程 id 为 ${PROCESS_ID} ☺☺☺☺☺ \033[0m"else echo "\033[41;37m ☺☺☺☺☺ 应用 ${App_Name} 已经被启动了 ☺☺☺☺☺ \033[0m"fi
#!/bin/bash
# 定义应用名称App_Name=toyapp
echo "\033[44;37m ☺☺☺☺☺ 开始停止 ${App_Name} 应用 ☺☺☺☺☺ \033[0m"ps -ef | grep ${App_Name} | grep -v grep | awk '{print$2}' | xargs killecho "\033[41;37m ☺☺☺☺☺ 应用 ${App_Name} 停止成功!☺☺☺☺☺ \033[0m"
应用启停脚本编写完成,执行脚本,蓝红搭配,sao 极了有没有?!
至此,Spring Boot 项目最基本的发布方式就完事了,可以直接执行脚本完成项目的启动和停止,爽歪歪!
4. 例行回顾
本文主要是对 Spring Boot 应用打包发布的探究,在面对引入三方依赖编译打包时,默认不会打进去,需要配置 includeSystemScope 方能包含 system 的三方依赖;接着重点讲解了如何用一行命令启动 Spring Boot 项目,以及如何把命令封装成脚本来对线上的应用进行发布操作。
如果你眼下运气欠佳,请不要气馁。一朵花的凋零荒芜不了整个春天,一次挫折也击垮不了整个人生。过去的已无法撤回,但未来还可努力书写。要相信,人生路上的每一次磨砺都是未来的铺垫 。