第 5-5 课: 如何打包部署 Spring Boot 项⽬

Spring Boot 使⽤了内嵌容器,因此它的部署⽅式也变得⾮常简单灵活,⼀⽅⾯可以将 Spring Boot 项⽬打包
成独⽴的 Jar 或者 War 包来运⾏,也可以单独打包成 War 包部署到 Tomcat 容器中运⾏,如果涉及到⼤规模
的部署 Jinkins 就成为最佳选择之⼀。
 
Spring Boot 默认集成 Web 容器,启动⽅式和普通 Java 程序⼀样, main 函数⼊⼝启动,其内置 Tomcat
器或 Jetty 容器,具体由配置来决定(默认 Tomcat )。

相关配置

多环境配置

在这⾥将介绍⼀下 Spring Boot 多环境配置⽂件,在我们开发过程中必定会⾯临多环境的问题,⽐如开发环
境、测试环境、⽣产环境,在不同的环境下会有不同的数据库连接池等配置信息。如果都写在⼀个配置⽂件
中,在不同的环境下启动需要⼿动修改对应的环境参数,这种⽅式容易出错且不够优雅。 Spring Boot ⽀持多
配置⽂件的使⽤,只需要启动时指定对应的配置⽂件即可。
 
⾸先在 pom.xml 中添加相关配置:

 
 dev
 
 dev
 
 
 true
 
 
 
 test
 
 test
 
 
 
 pro
 
 pro
 
 
GitChat


 
 
 src/main/resources
 true
 
 application-dev.properties
 application-pro.properties
 application-test.properties
 
 
 
 src/main/resources
 true
 
 application-${env}.properties
 
 
 
 
 
 org.springframework.boot
 spring-boot-maven-plugin
 
 
Spring Boot 中多环境配置⽂件名需要满⾜ application-{profifile}.properties 的格式,其中 {profifile} 对应环境
标识。在 resources ⽬录下创建以下三个⽂件。
pplication-dev.properties:开发环境
application-test.properties:测试环境
application-prod.properties:⽣产环境
不同的配置⽂件对应不同的环境,启动的时候通过参数设置来启⽤不同的配置,开发过程中在
application.properties ⽂件中通过 spring.profifiles.active 属性来设置,其值对应 {profifile} 值,⽣产中使⽤ --
spring.profifiles.active=dev 参数来控制加载某个配置⽂件。

配置项介绍

Server 的⼏个常⽤配置做个简单说明:
# 项⽬ contextPath,⼀般不⽤配置
server.servlet.context-path=/myspringboot
# 错误⻚,指定发⽣错误时,跳转的 URL
server.error.path=/error
# 服务端⼝
server.port=6060
# session最⼤超时时间(分钟),默认为30
server.session-timeout=60
# 该服务绑定 IP 地址,启动服务器时如本机不是该 IP 地址则抛出异常启动失败,只有特殊需求的情况下才
配置
# server.address=192.168.0.6
如果使⽤的是 Tomcat 还可以进⾏以下的配置:
 
# tomcat 最⼤线程数,默认为 200 
server.tomcat.max-threads=600 
# tomcat 的 URI 编码 
server.tomcat.uri-encoding=UTF-8 
# 存放 Tomcat 的⽇志、Dump 等⽂件的临时⽂件夹,默认为系统的 tmp ⽂件夹
server.tomcat.basedir=/tmp/log 
# 打开 Tomcat 的 Access ⽇志,并可以设置⽇志格式 
#server.tomcat.access-log-enabled=true 
#server.tomcat.access-log-pattern= 
# accesslog ⽬录,默认在 basedir/logs 
#server.tomcat.accesslog.directory= 
# ⽇志⽂件⽬录 
logging.path=/tmp/log 
# ⽇志⽂件名称,默认为 spring.log 
logging.file=myapp.log
以上的配置都为可选,在默认情况下都可不配置,项⽬中根据实际的使⽤情况来调整。

项⽬打包

打成 jar

内嵌容器技术的发展为 Spring Boot 部署打下了坚实的基础,内嵌容器不只在部署阶段发挥着巨⼤的作⽤,
在开发调试阶段也会带来极⼤的便利性,对⽐以往开发 Web 项⽬时配置 Tomcat 的繁琐,会让⼤家使⽤
Spring Boot 内嵌容器时有更深的感触。使⽤ Spring Boot 开发 Web 项⽬,不需要关⼼容器的环境问题,专
⼼写业务代码即可。
 
内嵌容器对部署带来的改变更多,现在 Maven Gradle 已经成了我们⽇常开发必不可少的构建⼯具,使⽤
这些⼯具很容易的将项⽬打包成 Jar 或者 War 包,在服务器上仅仅需要⼀条命令即可启动项⽬,我们以
Maven 为例来进⾏演示。
 
Maven 默认会将项⽬打成 jar 包,也可以显示指出打包⽅式。
com.neo
spring-boot-package
1.0.0

jar
Maven 打包会根据 pom 包中的 packaging 配置来决定是⽣成 Jar 包或者 War 包。
pom.xml 同⽬录下,执⾏以下命令:
cd 项⽬跟⽬录(和 pom.xml 同级)
mvn clean package
## 或者执⾏下⾯的命令
## 排除测试代码后进⾏打包
mvn clean package -Dmaven.test.skip=true
  • mvn clean 是清除项⽬ target ⽬录下的⽂件
  • mvn package 打包命令,可以和 mvn clean ⼀起执⾏
在使⽤ Maven 进⾏打包的时候,会⾃动对 test 包下⾯的测试⽤例进⾏测试,测试⽤例失败会给出错误提
示,并停⽌打包,可以利⽤这个功能来做项⽬的⾃动化测试,检测基本功能是否正确,也可以选择不执⾏这
些测试⽤例,启动时添加参数 -Dmaven.test.skip=true
 
打包完成后 jar 包会⽣成到 target ⽬录下,命名⼀般是 项⽬名 + 版本号 .jar” 的形式。
 
启动 jar 包命令:
 
java -jar target/spring-boot-package-1.0.0.jar
这种⽅式,只要控制台关闭,服务就会停⽌,⽣产中我们⼀般使⽤后台运⾏的⽅式来启动 :
 
nohup java -jar spring-boot-package-1.0.0.jar &
设置 jvm 参数:
java -Xms10m -Xmx80m -jar spring-boot-package-1.0.0.jar &
也可以在启动的时候选择读取不同的配置⽂件:
java -jar spring-boot-package-1.0.0.jar --spring.profiles.active=dev

gradle

如果使⽤的是 gradle ,使⽤下⾯命令打包:
gradle build
java -jar build/libs/mymodule-0.0.1-SNAPSHOT.jar
Spring Boot ⽀持在启动的时候添加定制,⽐如设置应⽤的堆内存、垃圾回收机制、⽇志路径等。

打成 war

打成 war 包也⾮常的简单,但需要添加⼀些额外的配置。
 
1 Maven 项⽬,修改 pom
jar
改为
war
2 )打包时排除 Tomcat
 

 org.springframework.boot
 spring-boot-starter-web


 org.springframework.boot
 spring-boot-starter-tomcat
 provided
在这⾥将 scope 属性设置为 provided ,这样在打包产⽣的 war 中就不会包含此 jar
 
3 )注册启动类
 
在项⽬的启动类中继承 SpringBootServletInitializer 并重写 confifigure() ⽅法:
@SpringBootApplication
public class PackageApplication extends SpringBootServletInitializer {
 @Override
 protected SpringApplicationBuilder configure(SpringApplicationBuilder applicat
ion) {
 return application.sources(PackageApplication.class);
 }
 public static void main(String[] args) {
 SpringApplication.run(PackageApplication.class, args);
 }
}
最后执⾏:
mvn clean package -Dmaven.test.skip=true
会在 target ⽬录下⽣成:项⽬名 + 版本号 .war ⽂件,复制到 Tomcat 服务器中启动即可。
 
打包成功输出的内容:
 
Results :
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 29.290 s
[INFO] Finished at: 2017-11-26T15:19:43+08:00
[INFO] Final Memory: 36M/354M
[INFO] ------------------------------------------------------------------------

gradle

如果使⽤的是 Gradle ,基本步骤和 Maven 类似, build.gradle 中添加 war 的⽀持,排除 spring-boot-starter
tomcat
...
apply plugin: 'war'
...
dependencies {
 compile("org.springframework.boot:spring-boot-starter-web:2.1.0.RELEASE"){
 exclude mymodule:"spring-boot-starter-tomcat"
 }
}
...
再使⽤构建命令:
gradle build
war 会⽣成在 build\libs ⽬录下。

部署运维

单个项⽬

简单粗暴

直接 kill 掉进程再次启动 jar 包:
ps -ef|grep java 
##拿到对于 Java 程序的 pid
kill -9 pid
## 再次重启
Java -jar xxxx.jar
当然这种⽅式⽐较传统和暴⼒,建议⼤家使⽤下⾯的⽅式来管理。

脚本执⾏

如果使⽤的是 Maven ,需要包含以下的配置:

 org.springframework.boot
 spring-boot-maven-plugin
 
 true
 
如果使⽤是 Gradle ,需要包含下⾯配置:
 
Spring Boot {
 executable = true
}
启动⽅式:
 
1 )可以直接 ./yourapp.jar 来启动
2 )注册为服务
 
也可以做⼀个软链接指向你的 jar 包并加⼊到 init.d 中,然后⽤命令来启动。
 
init.d 例⼦ :
ln -s /var/yourapp/yourapp.jar /etc/init.d/yourapp
chmod +x /etc/init.d/yourapp
这样就可以使⽤ stop 或者是 restart 命令去管理你的应⽤了。
/etc/init.d/yourapp start|stop|restart
或者
service yourapp start|stop|restart
如果是打包成独⽴的 war 包部署到 Tomcat 中,就按照 Tomcat 的相关命令来重启。当然以上只是单个项⽬
部署,假设我们有 1000 多个项⽬,如果再按照这种⽅式来打包上传启动的话,整个平台部署完成估计需要
⼏个⼩时,并且⾮常容易出错。在⼤量部署应⽤时,给⼤家介绍另外⼀款⾃动化部署神器 Jenkins

批量部署

Jenkins 是⽬前持续构建领域使⽤最⼴泛的⼯具之⼀,它是⼀个独⽴的开源⾃动化服务器,可⽤于⾃动化各
种任务,如构建、测试和部署软件。 Jenkins 可以通过本机系统包以 Docker 的⽅式部署项⽬,甚⾄可以通过
安装 Java Runtime Environment 的任何机器独⽴运⾏。
 
Jenkins 可以很好的⽀持各种语⾔(如 Java C# PHP 等)项⽬构建,也完全兼容 ant maven gradle
多种第三⽅构建⼯具,同时跟 svn git 能⽆缝集成,也⽀持直接与知名源代码托管⽹站,⽐如 GitHub
Bitbucket 直接集成。
 
说直⽩⼀点 Jenkins 就是专⻔来负责如何将代码变成可执⾏的程序包,将它部署到⽬标服务器中,并对其运
营状态(⽇志)进⾏监控的软件。⾃动化、性能、打包、部署、发布、发布结果⾃动化验证、接⼝测试、单
元测试等关于我们打包测试部署的⽅⽅⾯⾯ Jenkins 都可以很友好的⽀持。
 
Jenkins 搭建部署分为四个步骤:
 
  • 第⼀步,Jenkins 安装
  • 第⼆步,插件安装和配置
  • 第三步,Push SSH
  • 第四步,部署项⽬
具体的安装部署过程可以参考我博客上的⽂章: 使⽤ Jenkins 部署 Spring Boot
在这⾥主要看⼀下使⽤ Jenkins 部署 Spring Boot 的脚本。
DATE=$(date +%Y%m%d)
export JAVA_HOME PATH CLASSPATH
JAVA_HOME=/usr/java/jdk1.8.0_131
PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
CLASSPATH=.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$CLASSPATH
DIR=/root/xxx
JARFILE=xxx-1.0.0-SNAPSHOT.jar
if [ ! -d $DIR/backup ];then
 mkdir -p $DIR/backup
fi
cd $DIR
ps -ef | grep $JARFILE | grep -v grep | awk '{print $2}' | xargs kill -9
mv $JARFILE backup/$JARFILE$DATE
mv -f /root/Jenkins-in/$JARFILE .
java -jar $JARFILE > out.log &
if [ $? = 0 ];then
 sleep 30
 tail -n 50 out.log
fi
cd backup/
ls -lt|awk 'NR>5{print $NF}'|xargs rm -rf
⾸先导⼊相关环境变量,然后根据⽇期对项⽬进⾏备份, kill 掉正在执⾏的 Spring Boot 项⽬,将推送过来的
项⽬包放到对应⽬录下,使⽤ java -jar 命令来启动应⽤,最后将启动⽇志打印出来。
 
使⽤ Jenkin 之后,部署项⽬的步骤如下:
  • push 代码到 Github(或者 SVN) 触发 WebHook
  • Jenkins 从仓库拉去代码
  • Maven 构建项⽬、单元测试
  • 备份项⽬,停⽌正在运⾏的项⽬
  • 启动应⽤
  • 查看启动⽇志
使⽤ Jenkin 前期做⼀些简单的配置,后期当发布项⽬时只需要点击项⽬对应的发布按钮,就可以将项⽬从版
本库中拉取、打包、发布到⽬标服务器中,⼤⼤简化了运维后期的部署⼯作。
 

查看应⽤运⾏配置

 
可以根据 Java ⾃带的 jinfo 命令:
jinfo -flags pid
来查看 jar 启动后使⽤的是什么 gc 、新⽣代、⽼年代分批的内存都是多少,示例如下:
Attaching to process ID 5589, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
Non-default VM flags: -XX:CICompilerCount=2 -XX:InitialHeapSize=16777216 -XX:MaxHe
apSize=262144000
 -XX:MaxNewSize=87359488 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=5570560 -XX:OldS
ize=11206656 
 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
  • -XX:CICompilerCount:最⼤的并⾏编译数
  • -XX:InitialHeapSize -XX:MaxHeapSize:指定 JVM 的初始和最⼤堆内存⼤⼩
  • -XX:MaxNewSizeJVM 堆区域新⽣代内存的最⼤可分配⼤⼩
  • XX:+UseCompressedClassPointers: 压缩类指针
  • -XX:+UseCompressedOops: 压缩对象指针
  • -XX:+UseParallelGC:垃圾回收使⽤ Parallel 收集器

总结

Spring Boot 项⽬⽀持在不同环境下指定不同配置⽂件启动,⽅便开发⼈员在各个环节部署。 Spring Boot
为使⽤了内嵌容器,因此极⼤的优化了项⽬的部署难度,我们可以根据配置将 Spring Boot 打包成 Jar 或者
War 部署,单个项⽬可以使⽤命令⾏或者脚本的形式部署项⽬,如果涉及⼤量应⽤的部署运维,建议使⽤
Jenkins 发布 Spring Boot 项⽬,使⽤ Jinkins 可以以图形化的形式批量部署 Spring Boot 应⽤。
点击这⾥下载源码

你可能感兴趣的:(Spring,Boot,打包,部署)