Spring Boot 项目打包完美实践
Spring Boot 打包远程执行代码admin 发布于:2023-02-19 13:28:37
阅读:loading
前文中有两篇《Spring Boot 项目assembly打包实践》和《Spring Boot 项目打包静态资源分离实践》的文章来实践项目打包,本篇文章主要是来集二者所长,汇总实践出来一版本更加易于打包部署的实现,如果对打包部署缺乏较多的了解不妨先关注一下前面的两篇文章,本文则是回顾一下两种方式的优缺点,在此基础之上再整合出一版较为科学的实践结果,如前面两篇文章的优缺点如下。
1.1 Spring Boot 项目assembly打包实践
优点
(1)使用了强大的assembly插件,使得打包后的文件夹比较独立统一,也可利用插件将打包后的文件夹压缩等;
(2)打包按文件夹归类不同的文件夹(bin/conf/logs/runtime/lib),提供了简单的启停脚本;
(3)打包后的jar文件夹按类型归类,区分哪些是第三方开源的jar,哪些是本地jar,哪些是项目内部不同模块的jar(区分如此清楚至少有两个好处:1.很多时候可降低部署维护jar的成本,如果仅修改了项目内部的代码只需要部署项目内部的jar即可;2.可以通过Java -cp命令来指定不同jar中class文件加载的优先级,若需要修改一些第三方jar中的源码时,可以通过在项目内或本地修改jar的形式,通过优先级的加载来实现不修改开源的jar文件);
(4)提供启停命令的兼容细节,如脚本中设置了gc.log的文件夹和java.io.temp文件夹的设置,我们可以提前生成好需要的文件夹;
(5)支持按环境打包,默认为dev,另有test和prod环境,日志文件等其它配置文件均支持;
缺点
(1)未将静态资源和配置文件从jar中剥离,jar中还包含着有较多的静态资源文件,导致个别jar文件教导;
(2)无法做到修改资源文件后的适时生效;
优点
(1)将配置文件和资源文件从jar中剥离,使得jar中文件类型相对独立;
(2)配置文件和资源文件独立存放,资源文件的修改支持适时生效(已验证的范围为:静态资源文件和thymeleaf模板文件,未验证Excel和Freemarker等模板文件);
(3)运行脚本略简单,使用Java -jar运行;
缺点
(1)打包的结果显得有些半成品了,最终并未将所需的文件和文件夹归置在一个独立的文件夹中,除了包含打包后的文件夹(conf/lib/jar)还包含其它的文件夹;
(2)以熟悉掌握为主,不够专业和细致,距离企业级实践来讲并非完美;
<build>
<plugins>
<!-- 打JAR包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!-- 不打包资源文件(配置文件和依赖包分开) -->
<excludes>
<exclude>*.yaml</exclude>
<exclude>*.xml</exclude>
<exclude>prod/**</exclude>
<exclude>test/**</exclude>
<exclude>config/**</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<!-- MANIFEST.MF 中 Class-Path 加入前缀 -->
<classpathPrefix></classpathPrefix>
<!-- jar包不包含唯一版本标识 -->
<useUniqueVersions>false</useUniqueVersions>
<!--指定入口类 -->
<mainClass>cn.chendd.Bootstrap</mainClass>
</manifest>
<manifestEntries>
<!--MANIFEST.MF 中 Class-Path 加入资源文件目录 -->
<Class-Path>../conf/</Class-Path>
</manifestEntries>
</archive>
<outputDirectory>${project.build.directory}</outputDirectory>
</configuration>
</plugin>
<!-- 打包插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<executions>
<!-- 配置执行器 -->
<execution>
<id>assembly-admin</id>
<!-- 绑定到package生命周期阶段上 -->
<phase>package</phase>
<goals>
<!-- 只运行一次,会生拷贝响应的文件至输出目录 -->
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<!--打包文件夹目录名称,默认格式为artifactId-version-->
<finalName>chendd</finalName>
<descriptors>
<!--assembly配置文件路径-->
<descriptor>src/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
<!-- 打包环境参数 -->
<profiles>
<profile>
<id>dev</id>
<!-- 默认打包采取的模式 -->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<filters.envFolder>src/main/resources</filters.envFolder>
<filters.viewsFolder>src/main/views</filters.viewsFolder>
<filters.envName></filters.envName>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<filters.envFolder>src/main/resources/test</filters.envFolder>
<filters.viewsFolder>src/main/views</filters.viewsFolder>
<filters.envName>-test</filters.envName>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<filters.envFolder>src/main/resources/prod</filters.envFolder>
<filters.viewsFolder>src/main/views</filters.viewsFolder>
<filters.envName>-prod</filters.envName>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
</profiles>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
<!--
apache plugin项目地址:https://maven.apache.org/plugins/maven-assembly-plugin/assembly.html
<id>此程序集的id<id>
<format>常见的打包文件格式:zip、tar、tar.gz、jar、dir、war等</format>
<includeBaseDirectory>在最终存档中包含一个基本目录</includeBaseDirectory>
-->
<!--生成的根文件夹名称为:pom.xml中finalName定义的前缀 + '-' + 此处的id-->
<id>admin</id>
<formats>
<!--打包的文件格式,可以是:dir、war、zip、tar.gz-->
<format>dir</format>
</formats>
<!--是否在target目录下创建一个根文件夹,取名baseDirectory-->
<includeBaseDirectory>false</includeBaseDirectory>
<baseDirectory>admin-all</baseDirectory>
<!--指定要包含在程序集中的文件组-->
<fileSets>
<fileSet>
<directory>src/bin</directory>
<directoryMode>0755</directoryMode>
<fileMode>0777</fileMode>
<outputDirectory>bin</outputDirectory>
<lineEnding>unix</lineEnding>
</fileSet>
<fileSet>
<directory>${filters.envFolder}</directory>
<excludes>
<!--根据环境设置排除的目录,若打包为test环境时排除src/main/resources/test/test/**路径-->
<exclude>test/**</exclude>
<exclude>prod/**</exclude>
<!--此文件由下方特殊处理-->
<exclude>application${filters.envName}.yaml</exclude>
</excludes>
<outputDirectory>conf</outputDirectory>
</fileSet>
<!--创建statics文件夹用于存放静态资源文件-->
<fileSet>
<directory>${filters.viewsFolder}/statics</directory>
<outputDirectory>conf/statics</outputDirectory>
</fileSet>
<!--创建templates文件夹用于存放模板资源文件-->
<fileSet>
<directory>${filters.viewsFolder}/templates</directory>
<outputDirectory>conf/templates</outputDirectory>
</fileSet>
</fileSets>
<!--创建文件夹以及重命名资源文件-->
<files>
<!-- 重命名资源文件名称,但当文件不存在时报错了,使用copy-rename-maven-plugin插件解决 -->
<file>
<source>${filters.envFolder}/application${filters.envName}.yaml</source>
<outputDirectory>conf</outputDirectory>
<destName>application.yaml</destName>
<filtered>true</filtered>
</file>
<!--创建runtime文件夹用于启动命令时指定临时目录-Djava.io.tmpdir-->
<file>
<source></source>
<outputDirectory>runtime</outputDirectory>
</file>
<!--创建logs文件夹用于输出日志文件时的根目录-->
<file>
<source></source>
<outputDirectory>logs</outputDirectory>
</file>
</files>
<!--项目依赖的jar配置-->
<dependencySets>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>lib-jar</outputDirectory>
<!--是否解压缩jar文件-->
<unpack>false</unpack>
<!--依赖jar文件的范围-->
<scope>runtime</scope>
<!--排除项目内的jar-->
<excludes>
<exclude>cn.chendd*:*</exclude>
</excludes>
</dependencySet>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>lib-local</outputDirectory>
<unpack>false</unpack>
<!--将使用SystemPath依赖的本地jar拷贝至同级目录-->
<scope>system</scope>
<!--排除项目内的jar-->
<excludes>
<exclude>cn.chendd*:*</exclude>
</excludes>
</dependencySet>
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>lib-project</outputDirectory>
<unpack>false</unpack>
<includes>
<include>cn.chendd*:*</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>
打包命令可区分不同的环境,参考如下:
开发环境:clean compile package -Dmaven.test.skip=true -f pom.xml
测试环境:clean compile package -Ptest -Dmaven.test.skip=true -f pom.xml
生产环境:clean compile package -Pprod -Dmaven.test.skip=true -f pom.xml
【运行说明】
(1)conf目录为静态资源目录和配置文件目录,其中statics为静态资源目录,templates为thymeleaf模板路径,其它路径为classes中的配置文件;
(2)修改statics路径下的readme.txt文件,验证更新生效;
(3)在statics路径下增加lhk.jpg文件,验证增加文件生效;
(4)在templates目录下的usage目录的simple.html更新,验证修改模板文件生效(该文件内部有包含thymeleaf标签);
(5)本例验证项目源码可见:源码下载.zip;
(6)本例的实践是基于示例代码的“PackageAssembly”和“PackageJarResources”的实践总结而来;
(7)对于Java -jar的启动命令,我还是喜欢使用Java -cp命令,参考启动脚本为“java -Xmx256m -Xms256m -Xmn256m -XX:+UseG1GC -XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCTimeStamps -Xloggc:../logs/gc.log -Djava.io.tmpdir=../runtime -Dfile.encoding=utf-8 -Duser.timezone=GMT+8 -cp ../conf;../lib-local/*;../lib-project/*;../lib-jar/* cn.chendd.Bootstrap”,目前启动后的访问都还正常,更多的实践有待后续的实践检验了;
点赞