Spring Boot 解决FatJar, 实现配置和依赖与打包的jar分离

举报
KDD 发表于 2021/04/01 16:14:57 2021/04/01
【摘要】 背景Spring Boot提供了一个很好用的打包插件,名为spring-boot-maven-plugin, 通过这个插件可以实现spring boot工程仅需一个jar就能够启动的效果。(eg. java -jar xxx.jar)。这种做法的好处和坏处都显而易见, 好的地方就是启动打包都很简单,且方便。缺点就是打包之后如果需要更改配置或者修改代码,都需要重新打包,通常情况下这个jar...
  1. 背景
    Spring Boot提供了一个很好用的打包插件,名为spring-boot-maven-plugin, 通过这个插件可以实现spring boot工程仅需一个jar就能够启动的效果。(eg. java -jar xxx.jar)。这种做法的好处和坏处都显而易见, 好的地方就是启动打包都很简单,且方便。缺点就是打包之后如果需要更改配置或者修改代码,都需要重新打包,通常情况下这个jar都比较臃肿,本来只是修改一小部分东西,但是你不得不为了前面的方便付出一些牺牲,每次都需要重新出包,传包(如果是在服务器调试的话)。

  2. 解决办法

为了应对这种情况,我们可以通过其他的打包插件将配置和依赖从原有的臃肿的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 或者配置文件无需重新打整个的包。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。