Spring Boot 项目打包完美实践

Spring Boot 打包远程执行代码
placeholder image
admin 发布于:2023-02-19 13:28:37
阅读:loading

1.基本介绍

前文中有两篇《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.2 Spring Boot 项目打包静态资源分离实践

优点

(1)将配置文件和资源文件从jar中剥离,使得jar中文件类型相对独立;

(2)配置文件和资源文件独立存放,资源文件的修改支持适时生效(已验证的范围为:静态资源文件和thymeleaf模板文件,未验证Excel和Freemarker等模板文件);

(3)运行脚本略简单,使用Java -jar运行;

缺点

(1)打包的结果显得有些半成品了,最终并未将所需的文件和文件夹归置在一个独立的文件夹中,除了包含打包后的文件夹(conf/lib/jar)还包含其它的文件夹;

(2)以熟悉掌握为主,不够专业和细致,距离企业级实践来讲并非完美;

2.打包命令

2.1 pom.xml

<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>

2.2 assembly.xml

<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>

3.打包结果

image.png

打包命令可区分不同的环境,参考如下:

开发环境: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

4.运行结果

打包热部署.gif

【运行说明】

(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”,目前启动后的访问都还正常,更多的实践有待后续的实践检验了;


 点赞


 发表评论

当前回复:作者

 评论列表


留言区