一、前言刚开始实习不到一个月的时候,从师兄手中接手了团队的项目,当时第一次听到了 “大包”、“小包” 的概念,只见师兄一顿操作,使用 Maven 将项目进行了打包。当时不太理解,只是记得两点:
如果想让项目作为一个依赖提供给他人使用,则将项目打为 “小包” ;如果希望项目打出来 Jar 包可以作为一个独立服务运行,则将项目打为 “大包” 。也就是说,可以将项目打包为两类:一类是作为依赖提供给他人使用,一类是作为独立服务使用。 下面将从这两类来讲解使用 Maven 将项目打包的方式。
二、将项目打为小包所谓打包为 “小包”,其实就是仅打包项目中的代码到 JAR 包中,不打包依赖包 。 将项目打包为 “小包” 的做法很简单,就是在 pom.xml 文件中的
plugins
标签给注释掉即可,也就是不做任何打包插件的配置。如下图所示:
< build>
< finalName> community</ finalName>
</ build>
然后执行打包命令:
mvn clean package -Dmaven.test.skip= true
最后,会在当前项目的 target 目录生成一个 “小包”:
使用反编译工具查看 Jar 包具体内容:
从 Jar 包内容可以看出来,项目的依赖都以 Maven 依赖的形式保存在了
pom.xml
文件中,源码的部分只有项目本身的代码。这种 Jar 包就是所谓的 “小包”。
三、将项目打包为大包如果想要打包后的 Jar 包能够作为一个独立服务运行,必须满足以下两点:
在 Jar 包中的 META-INF/MANIFEST.MF
中指定 Main-Class
,这样才能确定程序的入口在哪里; 要能加载到依赖包。 所以我们将项目打包为大包的中心思想也就是实现上面两点。使用 Maven 将项目打包为大包的方式就比较多了。主要有以下三种方式:
方法一:使用 maven-jar-plugin
和 maven-dependency-plugin
插件 方法二:使用 maven-assembly-plugin
插件 方法三:使用 maven-shade-plugin
插件 注意 :对于 SpringBoot 项目,在初始的 pom.xml
文件中就提供了 spring-boot-maven-plugin
插件用于将项目打包为可执行 Jar 包,不建议再使用其他任何插件(包括下面的三种插件)打包。 方法一:使用 maven-jar-plugin
和 maven-dependency-plugin
插件此种打包方式有一个比较明显的缺点:打包后会在
target
目录下生成
lib
目录(存放依赖 Jar)和项目 Jar。也就是说由于依赖都存在于
lib
目录中,所以要想运行 Jar 包,必须将 Jar 包和
lib
目录放在同一个路径下。
pom.xml
文件中关于打包的配置信息如下:
< build>
< finalName> community</ finalName>
< plugins>
< plugin>
< groupId> org.apache.maven.plugins</ groupId>
< artifactId> maven-jar-plugin</ artifactId>
< configuration>
< archive>
< manifest>
< addClasspath> true</ addClasspath>
< classpathPrefix> lib/</ classpathPrefix>
< mainClass> com.ronz.community.CommunityApplication</ mainClass>
</ manifest>
</ archive>
</ configuration>
</ plugin>
< plugin>
< groupId> org.apache.maven.plugins</ groupId>
< artifactId> maven-dependency-plugin</ artifactId>
< executions>
< execution>
< id> copy-dependencies</ id>
< phase> package</ phase>
< goals>
< goal> copy-dependencies</ goal>
</ goals>
< configuration>
< outputDirectory> ${project.build.directory}/lib</ outputDirectory>
</ configuration>
</ execution>
</ executions>
</ plugin>
</ plugins>
</ build>
这个思想也比较简单。 首先说
maven-jar-plugin
插件,它的思想就是:指定启动类、指定依赖包相对于项目最终 Jar 包所在的路径、给
MANIFEST.MF
文件添加
Class-Path
属性(运行项目 Jar 包时会根据
Class-Path
属性来找到具体依赖 Jar 包的路径)。 接着是
maven-dependency-plugin
插件,它的主要思想就是:指定所有依赖被打包为 Jar 包后的存放路径。 pom.xml 文件配置完毕之后,就可以运行打包命令了:
mvn package -Dmaven.test.skip= true
打包完成后,会在项目的
target
目录下生成
lib
文件夹(存放项目的所有依赖)和项目的 Jar 包:
为了增强对这种方法的认识,通过反编译工具查看编译后生成的
community.jar
包,其内容如下:
可以看到,在
MANIFEST.MF
文件中生成了
Class-Path
属性,该属性的值是当前项目的所有依赖 Jar 包的路径(即
lib
目录中的 Jar 包);当然还有
MainClass
属性,由于图片尺寸的原因,没有截到。 这种方式打包出来的 Jar 包,在代码层面只包含了项目本身的代码。而项目的依赖都以 Jar 包的形式放在了项目 Jar 包同级别目录下的
lib
目录中,这些依赖 Jar 包的路径在
MANIFEST.MF
文件中都以路径的方式指明了。
方法二:使用 maven-assembly-plugin
插件使用 maven-assembly-plugin
插件打出来的包只有一个 Jar 包 ,这个 Jar 包中包含了项目代码以及依赖的代码。也就意味着此种方式打出来的 Jar 包可以直接通过
java -jar xxx.jar
的命令来运行。
pom.xml
文件中关于打包的配置信息如下:
< build>
< finalName> community</ finalName>
< plugins>
< plugin>
< groupId> org.apache.maven.plugins</ groupId>
< artifactId> maven-assembly-plugin</ artifactId>
< configuration>
< archive>
< manifest>
< mainClass> com.ronz.community.CommunityApplication</ mainClass>
</ manifest>
</ archive>
< descriptorRefs>
< descriptorRef> jar-with-dependencies</ descriptorRef>
</ descriptorRefs>
</ configuration>
< executions>
< execution>
< id> make-assembly</ id>
< phase> package</ phase>
< goals>
< goal> single</ goal>
</ goals>
</ execution>
</ executions>
</ plugin>
</ plugins>
</ build>
这个插件的使用思想也比较简单:首先还是指定启动类;然后配置描述符参数,这个是插件提供的预置参数,不用更改;接下来就是打包时追加的命令了。 然后执行 Maven 打包命令:
mvn clean package -Dmaven.test.skip= true
打包完成之后,会在
target
目录下生成一个 Jar 包:
使用反编译工具查看 Jar 包:
从上图中可以清楚的看到:
项目的所有依赖都以源码文件的形式整合在了一起 。
方法三:使用 maven-shade-plugin
插件(推荐使用)根据 Maven 的官方文档介绍,
maven-shade-plugin
是一个强大的打包插件。它同样
可以将项目的依赖以及项目的源码打包成一个可执行 Jar 包 。
pom.xml
文件中关于打包的配置信息如下:
< build>
< finalName> community</ finalName>
< plugin>
< groupId> org.apache.maven.plugins</ groupId>
< artifactId> maven-shade-plugin</ artifactId>
< version> 3.2.4</ version>
< executions>
< execution>
< phase> package</ phase>
< goals>
< goal> shade</ goal>
</ goals>
< configuration>
< transformers>
< transformer
implementation = " org.apache.maven.plugins.shade.resource.ManifestResourceTransformer" >
< mainClass> com.ronz.community.CommunityApplication</ mainClass>
</ transformer>
< transformer
implementation = " org.apache.maven.plugins.shade.resource.AppendingTransformer" >
< resource> META-INF/spring.handlers</ resource>
</ transformer>
< transformer
implementation = " org.apache.maven.plugins.shade.resource.AppendingTransformer" >
< resource> META-INF/spring.schemas</ resource>
</ transformer>
</ transformers>
</ configuration>
</ execution>
</ executions>
</ plugin>
</ plugins>
</ build>
这个配置思想很简单:首先指定执行
package
命令时附加命令,这个是固定的,不需要改变;接下来就是指定项目的启动类;然后就是配置一个文件合并操作,主要是因为有的项目可能会有重名的资源文件,为了避免前面的资源文件被后面的覆盖掉,可以将重名的配置文件合并为一个文件,对于无重名资源文件的项目则无需配置。 执行 Maven 打包命令:
mvn clean package -Dmaven.test.skip= true
打包完成之后,会在
target
目录下生成一个 Jar 包,此 Jar 包中也是将项目依赖的源码包含进来了,可以通过
java -jar xxx.jar
命令直接运行 Jar 包。
四、总结经过我的实际测试, 使用第二种方式的
assembly
打包出来的 Jar 包多多少少有些问题,但是使用第三种方式打包出来的 Jar 包一般都是可用的。所以在将项目打包为大包时,还是
推荐使用第三种打包的方式 。
参考