本篇文章小编给大家分享一下使用springboot打包成zip部署并实现优雅停机代码示例,文章代码介绍的很详细,小编觉得挺不错的,现在分享给大家供大家参考,有需要的小伙伴们可以来看看。
众所周知springboot项目,使用springboot插件打包的话,会打包成一个包含依赖的可执行jar,非常方便。只要有java运行环境的电脑上,运行java -jar xxx.jar就可以直接运行项目。
但是这样的缺点也很明显,如果我要改个配置,要将jar包中的配置文件取出来,修改完再放回去。这样做在windows下还比较容易。如果在linux上面就很费劲了。
另外如果代码中需要读取一些文件(比如说一张图片),也被打进jar中,就没办法像在磁盘中时一句File file = new File(path)代码就可以读取了。(当然这个可以使用spring的ClassPathResource来解决)。
还有很多公司项目上线后,都是增量发布,这样如果只有一个jar 的话,增量发布也是很麻烦的事情。虽然我是很讨厌这种增量发布的方式,因为会造成线上生产环境和开发环境有很多不一致的地方,这样在找问题的时候会走很多弯路。很不幸我现在在的项目也是这样的情况,而且最近接的任务就是用springboot搭建一个定时任务服务,为了维护方便,最后决定将项目打包成zip进行部署。
网上找到了很多springboot打包成zip的文章,不过基本都是将依赖从springboot的jar中拿出来放到lib目录中,再将项目的jar包中META-INF中指定lib到classpath中。这样做还是会有上面的问题。
最后我决定自己通过maven-assembly-plugin来实现这个功能。
打包
首先maven-assembly-plugin是将项目打包的一个插件。可以通过指定配置文件来决定打包的具体要求。
我的想法是将class打包到classes中,配置文件打包到conf中,项目依赖打包到lib中,当然还有自己编写的启动脚本在bin目录中。
如图
maven的target/classes下就是项目编译好的代码和配置文件。原来的做法是在assembly.xml中配置筛选,将该目录下class文件打包进classes中,除class文件打包到conf中(bin目录文件打包进bin目录,项目依赖打包进lib目录)。结果发现conf目录下会有空文件夹(java包路径)。
pom.xml
maven-assembly-plugin false assembly/assembly.xml make-assembly package single
assembly.xml
package zip true true lib ${groupId}:${artifactId} bin /bin 777 ${project.build.directory}/conf /conf **/*.class META-INF/* ${project.build.directory}/classes /classes **/*.class META-INF/*
其实这样是不影响项目运行的,但是我看着很难受,尝试了很多方法去修改配置来达到不打包空文件夹的效果。但是都没成功。
然后我换了个方式,通过maven-resources-plugin插件将配置文件在编译的时候就复制一份到target/conf目录下,打包的时候配置文件从conf目录中取。这样就可以避免打包空白文件夹到conf目录中的情况。
pom.xml
maven-resources-plugin compile-resources resources utf-8 true src/main/resources/ true *.yml src/main/resources/ false -resources resources utf-8 true src/main/resources/ true *.yml src/main/resources/ false ${project.build.directory}/conf org.springframework.boot spring-boot-maven-plugin maven-assembly-plugin false assembly/assembly.xml make-assembly package single
assembly.xml
package zip tar.gz true true lib ${groupId}:${artifactId} bin /bin 777 ${project.build.directory}/conf /conf ${project.build.directory}/classes /classes **/*.class META-INF/*
pom文件中resources插件配置了2个execution,一个是正常往classes中写配置文件的execution,一个是往conf写配置文件的execution。这样做的好处是不影响maven本身的打包逻辑。如果再配置一个springboot的打包插件,也可以正常打包,执行。
执行
原来打包成jar后,只要一句java -jar xxx.jar就可以启动项目。现在为多个文件夹的情况下,就要手动指定环境,通过java -classpath XXX xxx.xxx.MainClass来启动项目,所以写了启动脚本。
run.sh
#!/bin/bash #Java程序所在的目录(classes的上一级目录) APP_HOME=.. #需要启动的Java主程序(main方法类) APP_MAIN_CLASS="io.github.loanon.springboot.MainApplication" #拼凑完整的classpath参数,包括指定lib目录下所有的jar CLASSPATH="$APP_HOME/conf:$APP_HOME/lib/*:$APP_HOME/classes" s_pid=0 checkPid() { java_ps=`jps -l | grep $APP_MAIN_CLASS` if [ -n "$java_ps" ]; then s_pid=`echo $java_ps | awk '{print $1}'` else s_pid=0 fi } start() { checkPid if [ $s_pid -ne 0 ]; then echo "================================================================" echo "warn: $APP_MAIN_CLASS already started! (pid=$s_pid)" echo "================================================================" else echo -n "Starting $APP_MAIN_CLASS ..." nohup java -classpath $CLASSPATH $APP_MAIN_CLASS >./st.out 2>&1 & checkPid if [ $s_pid -ne 0 ]; then echo "(pid=$s_pid) [OK]" else echo "[Failed]" fi fi } echo "start project......" start run.cmd @echo off set APP_HOME=.. set CLASS_PATH=%APP_HOME%/lib/*;%APP_HOME%/classes;%APP_HOME%/conf; set APP_MAIN_CLASS=io.github.loanon.springboot.MainApplication java -classpath %CLASS_PATH% %APP_MAIN_CLASS%
这样就可以启动项目了。
停止
linux下停止tomcat一般怎么做?当然是通过运行shutdown.sh。这样做有什么好处呢?可以优雅停机。何为优雅停机?简单点说就是让代码把做了一半工作的做完,还没做的(新的任务,请求)就不要做了,然后停机。
因为做的是定时任务处理数据的功能。试想下如果一个任务做了一半,我给停了,这个任务处理的数据被我标记了在处理中,下次重启后,就不再处理,那么这些数据就一直不会再被处理。所以需要像tomcat一样能优雅停机。
网上查询springboot优雅停机相关资料。主要是使用spring-boot-starter-actuator,不过很多人说这个在1.X的springboot中可以用,springboot 2.X不能用,需要自己写相关代码来支持,亲测springboot 2.0.4.RELEASE可以用。pom文件中引入相关依赖。
pom.xml
4.0.0 org.springframework.boot spring-boot-starter-parent 2.0.4.RELEASE io.github.loanon spring-boot-zip 1.0.0-SNAPSHOT 1.8 UTF-8 UTF-8 UTF-8 UTF-8 ${java.version} ${java.version} org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-logging org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-autoconfigure-processor org.springframework.boot spring-boot-starter-quartz org.apache.httpcomponents httpclient org.apache.httpcomponents httpmime maven-resources-plugin compile-resources resources utf-8 true src/main/resources/ true *.yml src/main/resources/ false -resources resources utf-8 true src/main/resources/ true *.yml src/main/resources/ false ${project.build.directory}/conf org.springframework.boot spring-boot-maven-plugin maven-assembly-plugin false assembly/assembly.xml make-assembly package single
在application.yml中配置一下
application.yml
management: #开启监控管理,优雅停机 server: ssl: enabled: false endpoints: web: exposure: include: "*" endpoint: health: show-details: always shutdown: enabled: true #启用shutdown端点
启动项目,可以通过POST方式访问/actuator/shutdown让项目停机。
实际线上可能没办法方便的发送POST请求,所以写个类处理下
Shutdown.java
package io.github.loanon.springboot; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.HttpClients; import java.io.IOException; /** * 应用关闭入口 * @author dingzg */ public class Shutdown { public static void main(String[] args) { String url = null; if (args.length > 0) { url = args[0]; } else { return; } HttpClient httpClient = HttpClients.createDefault(); HttpPost httpPost = new HttpPost(url); try { httpClient.execute(httpPost); } catch (IOException e) { e.printStackTrace(); } } }
只要将启动脚本中的启动类改成Shutdown类,并指定请求的地址即可。
stop.sh
#!/bin/bash #Java程序所在的目录(classes的上一级目录) APP_HOME=.. #需要启动的Java主程序(main方法类) APP_MAIN_CLASS="io.github.loanon.springboot.MainApplication" SHUTDOWN_CLASS="io.github.loanon.springboot.Shutdown" #拼凑完整的classpath参数,包括指定lib目录下所有的jar CLASSPATH="$APP_HOME/conf:$APP_HOME/lib/*:$APP_HOME/classes" ARGS="http://127.0.0.1:8080/actuator/shutdown" s_pid=0 checkPid() { java_ps=`jps -l | grep $APP_MAIN_CLASS` if [ -n "$java_ps" ]; then s_pid=`echo $java_ps | awk '{print $1}'` else s_pid=0 fi } stop() { checkPid if [ $s_pid -ne 0 ]; then echo -n "Stopping $APP_MAIN_CLASS ...(pid=$s_pid) " nohup java -classpath $CLASSPATH $SHUTDOWN_CLASS $ARGS >./shutdown.out 2>&1 & if [ $? -eq 0 ]; then echo "[OK]" else echo "[Failed]" fi sleep 3 checkPid if [ $s_pid -ne 0 ]; then stop else echo "$APP_MAIN_CLASS Stopped" fi else echo "================================================================" echo "warn: $APP_MAIN_CLASS is not running" echo "================================================================" fi } echo "stop project......" stop stop.cmd @echo off set APP_HOME=.. set CLASS_PATH=%APP_HOME%/lib/*;%APP_HOME%/classes;%APP_HOME%/conf; set SHUTDOWN_CLASS=io.github.loanon.springboot.Shutdown set ARGS=http://127.0.0.1:8080/actuator/shutdown java -classpath %CLASS_PATH% %SHUTDOWN_CLASS% %ARGS%
这样就可以通过脚本来启停项目。
其他
关于停机这块还是有缺点,主要是安全性。如果不加校验都可以访问接口,别人也就可以随便让我们的项目停机,实际操作过程中我是通过将web地址绑定到127.0.0.1这个地址上,不允许远程访问。当然也可添加spring-security做严格的权限控制,主要项目中没有用到web功能,只是spring-quartz的定时任务功能,所以就将地址绑定到本地才能访问。而且项目本身也是在内网运行,基本可以保证安全。
忍者必须死34399账号登录版 最新版v1.0.138v2.0.72
下载勇者秘境oppo版 安卓版v1.0.5
下载忍者必须死3一加版 最新版v1.0.138v2.0.72
下载绝世仙王官方正版 最新安卓版v1.0.49
下载Goat Simulator 3手机版 安卓版v1.0.8.2
Goat Simulator 3手机版是一个非常有趣的模拟游
Goat Simulator 3国际服 安卓版v1.0.8.2
Goat Simulator 3国际版是一个非常有趣的山羊模
烟花燃放模拟器中文版 2025最新版v1.0
烟花燃放模拟器是款仿真的烟花绽放模拟器类型单机小游戏,全方位
我的世界动漫世界 手机版v友y整合
我的世界动漫世界模组整合包是一款加入了动漫元素的素材整合包,
我的世界贝爷生存整合包 最新版v隔壁老王
我的世界MITE贝爷生存整合包是一款根据原版MC制作的魔改整