Spring Boot 解决FatJar, 实现配置和依赖与打包的jar分离
-
背景
Spring Boot提供了一个很好用的打包插件,名为spring-boot-maven-plugin, 通过这个插件可以实现spring boot工程仅需一个jar就能够启动的效果。(eg. java -jar xxx.jar)。这种做法的好处和坏处都显而易见, 好的地方就是启动打包都很简单,且方便。缺点就是打包之后如果需要更改配置或者修改代码,都需要重新打包,通常情况下这个jar都比较臃肿,本来只是修改一小部分东西,但是你不得不为了前面的方便付出一些牺牲,每次都需要重新出包,传包(如果是在服务器调试的话)。 -
解决办法
为了应对这种情况,我们可以通过其他的打包插件将配置和依赖从原有的臃肿的jar中分离出来。具体做法如下:
弃用 spring-boot-maven-plugin 插件(这只是一种方式,不弃用通过其他的手段应该也能实现),新增 maven-jar-plugin 和 maven-assembly-plugin两个打包插件,第一个是定义了你的原生的jar里面包含哪些内容以及他的MF文件中的内容。第二个是组织打包后的产物的组织形式,注意是打包后产物的组织形式。
一个样例:
<build>
<finalName>xxx</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!--不打包资源文件-->
<excludes>
<exclude>config/*.*</exclude>
</excludes>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<!--此配置比较坑,说明jar是否使用唯一标识,如果你的依赖有snapshot的依赖就要小心了,容易出现ClassNotFound的情况-->
<!--<useUniqueVersions>false</useUniqueVersions>-->
<mainClass>xxxxx.xxx</mainClass>
</manifest>
<manifestEntries>
<!--MANIFEST.MF 中 Class-Path 加入资源文件目录,此处加上snapshot这个jar是因为这个jar没有被发布到maven仓,打出来的mf文件的classpath不会自动包含此jar,故此手动增加-->
<Class-Path>./ lib/xxx-SNAPSHOT.jar</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>bin-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>${project.basedir}/src/main/java/xxx/assembly.xml</descriptor>
</descriptors>
<finalName>${release.package.title}_${release.package.version}</finalName>
<attach>false</attach>
<appendAssemblyId>false</appendAssemblyId>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
``
assembly的xml文件的示例:
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>kafka-ui</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<scope>runtime</scope>
<includes>
<include>*:*</include>
</includes>
<useProjectArtifact>false</useProjectArtifact>
<useTransitiveDependencies>true</useTransitiveDependencies>
<outputDirectory>xxx/lib</outputDirectory>
<fileMode>750</fileMode>
<directoryMode>600</directoryMode>
<useStrictFiltering>true</useStrictFiltering>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.basedir}/bin</directory>
<outputDirectory>xxx/yyy</outputDirectory>
</fileSet>
</fileSets>
</assembly>
``
j基于此文件你可以打出一个任意组织结构的软件包产物,本示例打出的是一个压缩包形式的产物,组织形式可以随意整合,值得注意的一点是classpath的路径一定要和最后的产物中的对应。例如样例中,我定义的classpath的前缀为lib,那么MF文件中的classpath就会以lib/xxx.jar lib/yyy.jar的形式来组成,我的产物的结构也是本工程的jar和lib在同级目录下。
lib
bin
config
xxxjar
此时可以直接通过java -jar xxx.jar命令来启动了。 修改依赖的jar 或者配置文件无需重新打整个的包。
- 点赞
- 收藏
- 关注作者
评论(0)