先点赞再看,养成好习惯
Spring Boot 的打包插件用着很爽吧,直接把源码和全部依赖打成一个 Jar 包还能直接java -jar
运行。那若是非 Spring Boot 项目,想打成一个可执行的 Jar 包该怎么办呢?html
别慌,Maven 这种老牌构建工具,搞定这个事情还不是轻轻松松!
java
下面介绍一些其余的 Maven 插件,一样能够直接将 Maven 项目打包成一个可执行的 Jar 包(uber jar/executable jar),并且功能更强大,应用场景更丰富!
git
关于这个 uber jar/executable jar 的名称由来,能够参考我以前的一篇文章《Executable Jar/Uber Jar/Shade Jar/Shadow Jar/Fat Jar 究竟是什么东西?》github
maven-dependency-plugin是 Maven 的一个内置插件,从名字就能看出来,它的功能就是处理依赖的。内置了不少目标(goals),功能很是全:spring
经过 unpack-dependencies
这个目标来解压依赖的包/源码,就能够完成一个 all-in-one 的打包方式:apache
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>unpack-dependencies</id> <!-- 绑定到 prepare-package 阶段 --> <phase>prepare-package</phase> <goals> <goal>unpack-dependencies</goal> </goals> <configuration> <includeScope>runtime</includeScope> <outputDirectory>${project.build.outputDirectory}</outputDirectory> </configuration> </execution> </executions> </plugin>
这个 unpack 的方式,会把全部依赖包(内部模块依赖和外部模块依赖)都“解压”,就是说会把依赖包的代码(class)都拷贝到 outputDirectory 目录里,相似一个合并的操做,结果就像这样:
而后再给 Jar 指定一个 main-class 让他直接可执行:segmentfault
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <mainClass> com.github.kongwu.mavenbuild.BuildExample </mainClass> </manifest> </archive> </configuration> </plugin>
固然!这个插件能干的事可不止这一种……看看上面的命令就知道,它功能很是多,这里介绍的只是它的一个小功能。app
maven-shade-plugin 也是 Maven 内置的一款插件,也能够直接打一个可执行 Jar 出来。和 dependency 插件效果同样,也是“解压”的模式,将全部依赖包的 class 放在一块儿,配置一个 transformer 和 mainClass 就行:maven
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <shadedArtifactAttached>true</shadedArtifactAttached> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.github.kongwu.mavenbuild.BuildExample</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
构建后的默认 jar 文件为:${artifactId}-${version}-shaded.jar
,不喜欢的话你也能够经过<outputFile>
去修改输出的 jar 文件spring-boot
这个插件的精髓在 shade ,而这个“解压”只是基本的功能。
有没有以为这个插件名字很奇怪,shade
是什么意思?
shade机翻为阴影、遮蔽,shade jar 是指将 jar 包及其依赖包打包到一个 jar 文件内,同时提供 shade“遮蔽 / 重命名” 某些依赖包的功能
关于 shade
的详细解释,能够参考个人另外一篇文章《Shade Jar/Shadow Jar 的解释》
最后介绍的这个 maven-assembly-plugin 插件,算是 maven 里最强的构建插件了,虽然它有用的 goal 只有一个,但功能真的很是很是强大:
好比 Zookeeper/Nacos/Arthas/Jenkins ,或者最近比较火的 pulsar 之类须要独立运行的软件,不少都是用这个插件构建的
先看它的一个简单场景,构建一个可执行 Jar 包:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <archive> <manifest> <mainClass> com.github.kongwu.mavenbuild.BuildExample </mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </execution> </executions> </plugin>
和上面两个插件效果同样,都是“解压”的方式,默认构建的文件为 ${artifactId}-${version}-jar-with-dependencies.jar
这么强大的插件,只拿他构建一个 uber jar 可有点太浪费了,若是只是简单的 uber jar 场景,用前面两种方式就足够了。
因此这个插件更适合复杂的构建需求,简单的uber jar
场景拿这种加特林级别的工具备一点浪费了……
来看看 Nacos 中的使用方式:
在 Nacos 的源码中,单独放了一个 distribution 的模块用于构建,借助 assembly 插件 + profile 功能,能够很方便的构建出各类环境的 bin 包:
<!-- nacos distribution/pom.xml--> <profile> <id>release-nacos</id> <dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>nacos-console</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptors> <descriptor>release-nacos.xml</descriptor> </descriptors> <tarLongFileMode>posix</tarLongFileMode> </configuration> <executions> <execution> <id>make-assembly</id> <phase>install</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> <finalName>nacos</finalName> </build> </profile> <profile> <id>release-core</id> <dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>nacos-core</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <id>release-core</id> <goals> <goal>single</goal> </goals> <phase>package</phase> <configuration> <descriptors> <descriptor>release-core.xml</descriptor> </descriptors> <appendAssemblyId>false</appendAssemblyId> </configuration> </execution> </executions> </plugin> </plugins> <finalName>nacos-core</finalName> </build> </profile>
Nacos 这种构建方式,也是比较“主流”的方式了,若是哪天你有构建独立运行包的需求,相信你也会用这种方式。
完整代码放在https://github.com/kongwu-/maven-build-examples/blob/master/pom.xml ,有兴趣的小伙伴能够拉下来试试
好了,介绍完了这几种插件构建 uber-jar 的玩法,如今作个对比:
dependency | shade | assembly | |
---|---|---|---|
优势 | goals 丰富,除了 unpack 还有不少其余的功能,好比清理/查看依赖树等等 | 专为 uber-jar 而生,并且支持 shade 功能,若是有重定位的需求,只能选它 | 功能最强,配置很是灵活,但没有 shade 功能 |
缺点 | 毕竟只是个处理依赖的插件,在构建方面的功能比较弱 | 复杂的构建需求下,功能会有些不足 | 没有 shade 功能,并且配置比较复杂 |
应用场景 | 适合简单的 uber-jar 功能 | 最适合 uber-jar 的构建,配合 shade 功能简直完美 | 适合复杂场景下的构建,不止是 uber jar |
本文介绍的 3 种插件,他们在构建 uber jar
的机制上和 Spring Boot 有所不一样:
Spring Boot 构建插件将会将依赖的 Jar 包打在 uber jar
内,是一种 "jars-in-a-jar" 的方式, 经过它的自定义 ClassLoader 去加载 Jar 包内的 Jar 包;而上面介绍的几种插件,并不会干预 mainClass 和 ClassLoader ,没法作到加载 Jar 包内的 Jar 包,因此都是经过“解压”的方式。
注意,Spring Boot 的构建插件,不仅能用在 Spring Boot 项目中。它的核心功能仍是构建,只是把启动类换成了 Spring Boot 的,而后经过它自定义的 ClassLoader 来加载。
因此,用spring-boot-maven-plugin
将一些非 Spring(Boot) 项目打包成一个 uber jar
也彻底没问题,JDK 和 Maven 的版本匹配就好。
关于以上几个插件的详细功能,能够参考下面插件的官方文档,Maven 的文档仍是比较详细的:
附上一张本身重绘的 Maven default 生命周期图,仍是比较清晰的,标明了每一个 phase 对应的不一样 plugin 的不一样 goal,若有须要自行保存(原图略大,点击查看大图)
原创不易,禁止未受权的转载。若是个人文章对您有帮助,就请点赞/收藏/关注鼓励支持一下吧❤❤❤❤❤❤