文章目录
- 最基础的 spring-boot-maven-plugin 使用
- 指定入口类
- 安装部署原始 Jar 包到仓库
- 保持原始Jar包名称,为 spring-boot-maven-plugin 生成的Jar包添加名称后缀
- 打包时排除依赖
- 建议将生成的Jar解压后了解一下整体结构
- 与其他常用打包插件比较
本文是对 spring-boot-maven-plugin
常用配置的介绍,更详细的学习请参照 Spring Boot Maven Plugin 官方文档
通过使用 spring-boot-maven-plugin
插件进行 Maven 的打包操作,可以将项目中依赖的 Jar 包一同添加到最终的项目 Jar 包内,这个插件有很多执行目标,对于打包来说,主要使用 repackage
目标,建议使用时与 Maven 生命周期的 package
阶段绑定
不管 pom.xml
是否声明了 Maven 的默认打包插件 maven-jar-plugin
,也不管是否声明了其他打包插件,maven-jar-plugin
都会在 package
阶段最先执行,而 spring-boot-maven-plugin
插件的 repackge
目标,正是对 maven-jar-plugin
打包后的 Jar 包进行二次打包,同时将项目依赖的 Jar 添加进去
这中打包后带依赖的 Jar 包一般称为 uper-jar
或 fat-jar
最基础的 spring-boot-maven-plugin 使用
这个插件的最基础使用方式非常简单,pom.xml
中添加如下配置即可,重点在 15~29 行:
<!-- 模拟项目使用了依赖 -->
<dependencies>
<!-- 依赖 commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
</dependencies>
<!-- 对项目构建进行配置 -->
<build>
<plugins>
<!-- 引入 spring-boot-maven-plugin 插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<executions>
<execution>
<!-- 绑定 Maven 生命周期的 package 阶段 -->
<phase>package</phase>
<goals>
<!-- package 阶段执行时,让其调用插件的 repackage 目标 -->
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
上面的配置添加后,我们就可以在 pom.xml
的所在目录运行 Maven 生命周期命令 mvn package
,当命令运行后,会将打包结果存放到 ${project.build.directory}
中(默认是 target 目录),如下图:
上图中,我们重点关注两个文件:
-
ares5k-package-1.0-SNAPSHOT.jar:
spring-boot-maven-plugin
对maven-jar-plugin
生成的 Jar 包进行二次打包后的 Jar 包,这个 Jar 包内已经包函项目的依赖了 -
ares5k-package-1.0-SNAPSHOT.jar.original:原始 Jar 包,
maven-jar-plugin
生成的不包含项目依赖的 Jar 包,spring-boot-maven-plugin
为了避免原始 Jar 包和新 Jar 包名字冲突,对原始 Jar 包进行了重命名,添加了original
后缀
对 ares5k-package-1.0-SNAPSHOT.jar
进行解压后,可以在 \BOOT-INF\lib
目录内看到项目依赖的 Jar 包:
虽然配置中没有指定入口类,但是这个 Jar 包仍然是可执行的,其在打包时会在 ${project.build.outputDirectory}(默认是 target/classes)
目录中依次向内查找,直至找到 .class
文件为止,那么这个 .class
文件就是我们的入口类并被添加到项目的 MANIFEST.MF
中,如果在同一目录内出现多个 .class
文件,那么最后一个会成为入口类,例如下图:
指定入口类
想打破 spring-boot-maven-plugin
自动查找入口类的规则,从而自定义入口类,参考 19~22 行配置即可 :
<build>
<plugins>
<!-- 引入 spring-boot-maven-plugin 插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<executions>
<execution>
<!-- 绑定 Maven 生命周期的 package 阶段 -->
<phase>package</phase>
<goals>
<!-- package 阶段执行时,让其调用插件的 repackage 目标 -->
<goal>repackage</goal>
</goals>
</execution>
</executions>
<!-- 修改插件属性 -->
<configuration>
<!-- 指定入口类 -->
<mainClass>com.ares5k.AA</mainClass>
</configuration>
</plugin>
</plugins>
</build>
安装部署原始 Jar 包到仓库
配置 spring-boot-maven-plugin
后,当执行 mvn install 或 mvn deploy
时,会将带依赖的 Jar 包安装或部署到仓库,有时候我们希望测试方便所以希望本地的包是包函依赖的,而安装部署的是原始包,这时候就可以如下配置,20~23 行:
<!-- 对项目构建进行配置 -->
<build>
<plugins>
<!-- 引入 spring-boot-maven-plugin 插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<executions>
<execution>
<!-- 绑定 Maven 生命周期的 package 阶段 -->
<phase>package</phase>
<goals>
<!-- package 阶段执行时,让其调用插件的 repackage 目标 -->
<goal>repackage</goal>
</goals>
</execution>
</executions>
<!-- 修改插件属性 -->
<configuration>
<!-- 将原始包安装或部署到仓库 -->
<attach>false</attach>
</configuration>
</plugin>
</plugins>
</build>
保持原始Jar包名称,为 spring-boot-maven-plugin 生成的Jar包添加名称后缀
前面演示了,spring-boot-maven-plugin
执行 repackage
后会将 原始 Jar 包 重命名为 .original
结尾的形式,如果想保持原始 Jar 包的名称,那么就需必须修改新 Jar 包的名称,不然会命名冲突,通过如下方式可以为 新 Jar 包 添加名称后缀,20~24 行:
<!-- 对项目构建进行配置 -->
<build>
<plugins>
<!-- 引入 spring-boot-maven-plugin 插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<executions>
<execution>
<!-- 绑定 Maven 生命周期的 package 阶段 -->
<phase>package</phase>
<goals>
<!-- package 阶段执行时,让其调用插件的 repackage 目标 -->
<goal>repackage</goal>
</goals>
</execution>
</executions>
<!-- 修改插件属性 -->
<configuration>
<!-- 给 spring-boot-maven-plugin 生成的 Jar 包添加名称后缀,
设置后 原始 Jar 包就不会改名为 .original 形式了-->
<!-- 这个地方名称随便写 -->
<classifier>spring-boot</classifier>
</configuration>
</plugin>
</plugins>
</build>
效果如下:
打包时排除依赖
打包时排除不需要的依赖,20~29 行:
<!-- 对项目构建进行配置 -->
<build>
<plugins>
<!-- 引入 spring-boot-maven-plugin 插件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.7.RELEASE</version>
<executions>
<execution>
<!-- 绑定 Maven 生命周期的 package 阶段 -->
<phase>package</phase>
<goals>
<!-- package 阶段执行时,让其调用插件的 repackage 目标 -->
<goal>repackage</goal>
</goals>
</execution>
</executions>
<!-- 修改插件属性 -->
<configuration>
<!-- 排除打包后不需要的依赖 -->
<excludes>
<!-- 排除 commons-lang3 -->
<exclude>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
建议将生成的Jar解压后了解一下整体结构
spring-boot-maven-plugin
打包后的项目 Jar 包中,不仅仅只是添加了依赖的 Jar 包,还多了很多 Spring 自己的文件,比如 META-INF/MANIFEST.MF
中真正的入口类其实是 Spring 的类,并不是我们设置的入口类,而我们设置的入口类是被 Spring 的这个类调用后才运行起来的。还有很多小细节,感兴趣的建议将项目Jar 解压后,研究一下
与其他常用打包插件比较
除了 spring-boot-maven-plugin
之外,常用的打包插件还有 maven-jar-plugin
和 maven-shade-plugin
,使用方法在我其他文章中也有记录,在此将它们作一个简单的比较
spring-boot-maven-plugin
spring-boot-maven-plugin
是 Spring 提供的一个 Maven 打包插件,可以通过 maven 的插件命令运行,但是一般习惯将它与 maven 生命周期绑定,然后通过 maven 生命周期命令运行,它的特点是可以将项目中依赖的 Jar 包添加到最终生成的项目 Jar 包中
spring-boot-maven-plugin
主要是对 maven-jar-plugin
生成的项目 Jar 包进行二次打包,并将项目依赖的 Jar 包添加进项目的 Jar 包中
maven-jar-plugin
maven 生命周期中 package
阶段的默认插件,不管是否在 pom.xml
中主动声明,也不管是否有其他的 package
阶段插件被绑定,其在 package
阶段都会被最先执行
使用 maven-jar-plugin
打包时,不会将依赖的 Jar 包添加到生成的项目 Jar 包中,所以当项目中使用依赖时,需要自己准备依赖的 Jar 包,这样 maven-jar-plugin
打出的项目 Jar 包才能被成功运行
maven-shade-plugin
maven-shade-plugin
也可以将项目的依赖打进最终的项目 Jar 包中,但是其与 spring-boot-maven-plugin
不同的是,spring-boot-maven-plugin
是直接将依赖的 Jar 包放进项目的 Jar 包中,而 maven-shade-plugin
则是将依赖的 Jar 包解压,然后将解压后的文件放进最终的项目 Jar 包中
maven-shade-plugin
将依赖的 Jar 包解压后添加到项目的 Jar 包中的做法,为 maven-shade-plugin
带来了另一个重要的功能 <重命名>,因为将依赖的 Jar 包解压后都是以文件形式存在,所以 maven-shade-plugin
支持对对依赖的某个具体文件进行重命名,maven-shade-plugin
在重命名时,不只是将文件名字修改,连我们项目中对其引用的地方都会一同修改
重命名的做法可以避免版本冲突,想详细了解的可以参考我 maven-shade-plugin
的文章