一、前言

刚开始实习不到一个月的时候,从师兄手中接手了团队的项目,当时第一次听到了 “大包”、“小包” 的概念,只见师兄一顿操作,使用 Maven 将项目进行了打包。当时不太理解,只是记得两点:

  1. 如果想让项目作为一个依赖提供给他人使用,则将项目打为 “小包”;
  2. 如果希望项目打出来 Jar 包可以作为一个独立服务运行,则将项目打为 “大包”。

也就是说,可以将项目打包为两类:一类是作为依赖提供给他人使用,一类是作为独立服务使用。

下面将从这两类来讲解使用 Maven 将项目打包的方式。

二、将项目打为小包

所谓打包为 “小包”,其实就是仅打包项目中的代码到 JAR 包中,不打包依赖包。

将项目打包为 “小包” 的做法很简单,就是在 pom.xml 文件中的 plugins 标签给注释掉即可,也就是不做任何打包插件的配置。如下图所示:

<build><!-- 项目最终打包成的名字 --><finalName>community</finalName>
</build>

然后执行打包命令:

# 先执行 clean,再执行 package,并且跳过测试用例的执行
mvn clean package -Dmaven.test.skip=true

最后,会在当前项目的 target 目录生成一个 “小包”:

使用反编译工具查看 Jar 包具体内容:

从 Jar 包内容可以看出来,项目的依赖都以 Maven 依赖的形式保存在了 pom.xml 文件中,源码的部分只有项目本身的代码。这种 Jar 包就是所谓的 “小包”。

三、将项目打包为大包

如果想要打包后的 Jar 包能够作为一个独立服务运行,必须满足以下两点:

  1. 在 Jar 包中的 META-INF/MANIFEST.MF 中指定 Main-Class,这样才能确定程序的入口在哪里;

  2. 要能加载到依赖包。

所以我们将项目打包为大包的中心思想也就是实现上面两点。使用 Maven 将项目打包为大包的方式就比较多了。主要有以下三种方式:

  • 方法一:使用 maven-jar-pluginmaven-dependency-plugin 插件
  • 方法二:使用 maven-assembly-plugin 插件
  • 方法三:使用 maven-shade-plugin 插件

注意:对于 SpringBoot 项目,在初始的 pom.xml 文件中就提供了 spring-boot-maven-plugin 插件用于将项目打包为可执行 Jar 包,不建议再使用其他任何插件(包括下面的三种插件)打包。

方法一:使用 maven-jar-pluginmaven-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><!-- 会在 MANIFEST.MF 中生成 Class-Path 项 --><!-- 系统会根据 Class-Path 项配置的路径加载依赖 --><addClasspath>true</addClasspath><!-- 指定依赖包所在目录,相对于项目最终 Jar 包的路径 --><classpathPrefix>lib/</classpathPrefix><!-- 指定 MainClass --><mainClass>com.ronz.community.CommunityApplication</mainClass></manifest></archive></configuration></plugin><!-- 配置依赖包 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><!-- 相当于执行 mvn 命令,将依赖打包到指定目录 --><executions><execution><id>copy-dependencies</id><phase>package</phase><goals><goal>copy-dependencies</goal></goals><configuration><!--将依赖打包至 target 下的 lib 目录--><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 文件配置完毕之后,就可以运行打包命令了:

# 跳过测试用例执行 package 命令
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><!-- 相当于在执行 package 打包时,在后面加上 assembly:single  --><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins></build>

这个插件的使用思想也比较简单:首先还是指定启动类;然后配置描述符参数,这个是插件提供的预置参数,不用更改;接下来就是打包时追加的命令了。

然后执行 Maven 打包命令:

# 先后执行 clean、package,并跳过测试文件的执行
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><!-- 指定启动类 --><transformerimplementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><mainClass>com.ronz.community.CommunityApplication</mainClass></transformer><!-- 下面的配置仅针对存在同名资源文件的情况,如没有则不用配置--><!-- 有些项目包可能会包含同文件名的资源文件(例如属性文件)--><!-- 为避免覆盖,可以将它们的内容合并到一个文件中 --><transformerimplementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"><resource>META-INF/spring.handlers</resource></transformer><transformerimplementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"><resource>META-INF/spring.schemas</resource></transformer></transformers></configuration></execution></executions></plugin></plugins>
</build>

这个配置思想很简单:首先指定执行 package 命令时附加命令,这个是固定的,不需要改变;接下来就是指定项目的启动类;然后就是配置一个文件合并操作,主要是因为有的项目可能会有重名的资源文件,为了避免前面的资源文件被后面的覆盖掉,可以将重名的配置文件合并为一个文件,对于无重名资源文件的项目则无需配置。

执行 Maven 打包命令:

# 先后执行 clean、package,并跳过测试文件的执行
mvn clean package -Dmaven.test.skip=true

打包完成之后,会在 target 目录下生成一个 Jar 包,此 Jar 包中也是将项目依赖的源码包含进来了,可以通过 java -jar xxx.jar 命令直接运行 Jar 包。

四、总结

经过我的实际测试, 使用第二种方式的 assembly 打包出来的 Jar 包多多少少有些问题,但是使用第三种方式打包出来的 Jar 包一般都是可用的。所以在将项目打包为大包时,还是推荐使用第三种打包的方式。

参考

  • Apache Maven Shade Plugin
  • Apache Maven Assembly Plugin
  • maven 打包项目的几种方式

Maven 的打包方式相关推荐

  1. maven 常用打包方式汇总

    通用的三种打包 1.方式一: 最小化打包 maven-jar-plugin 用途: 可以用来发布maven仓库 或最小化共享 一般不包含第三方依赖, 可以结合maven-dependency-plug ...

  2. IDEA中Maven项目打包方式

    方式一: 直接打包,不打包依赖包,仅打包出项目中的代码到JAR包中,可称为架包.在其他应用中运行时,必须保证其上面有相应的依赖包,才能运行. maven-->Lifecyle-->Clea ...

  3. Maven的三种打包方式(jar、shade、assembly)

    文章目录 01 引言 02 assembly打包 2.1 介绍 2.2 使用 2.3 字段解析 03 jar打包 3.1 介绍 3.2 使用 3.3 字段解析 04 shade打包 4.1 介绍 4. ...

  4. IDEA MAVEN项目打包成jar包的两种简单方式

    IDEA MAVEN项目打包成jar包的两种简单方式 准备了两个打包方法 1.IEDA自带打包方法 2.用Maven插件maven-shade-plugin打包 IDEA自带打包 适用于任何打包,稍微 ...

  5. maven三种打包方式详解

    目录 maven常用打包命令 1 方法一:使用maven-jar-plugin和maven-dependency-plugin插件打包 2 方法二:使用maven-assembly-plugin插件打 ...

  6. 探究maven项目的打包方式

    前言 现在都是使用idea中maven插件来打包项目,因此此文章将基于idea中的maven插件打包. 概念 打包分为小包和大包两种概念: 小包:只打包我们写的代码,不打包代码依赖的其他jar包. 大 ...

  7. Maven项目打包为jar的几种方式

    Maven项目打包为jar的几种方式 这里收集整理下以往打包MAVEN项目为JAR包的各种方式 ##直接打包,不打包依赖包 直接打包,不打包依赖包,仅打包出项目中的代码到JAR包中.在POM中添加如下 ...

  8. MAVEN的三种打包方式

    MAVEN的三种打包方式 Maven可以使用mvn package指令对项目进行打包,如果使用Java -jar xxx.jar执行运行jar文件,会出现"no main manifest ...

  9. 解放双手 | Jenkins + gitlab + maven 自动打包部署项目

    前言 记录 Jenkins + gitlab + maven 自动打包部署后端项目详细过程! 需求背景 不会偷懒的程序员不是好码农,传统的项目部署,有时候采用本地手动打包,再通过ssh传到服务器部署运 ...

最新文章

  1. IntelliJ IDEA导入JDK出现The selected directory is not a valid home for JDK问题的解决方法
  2. 缓存区溢出检测工具BED
  3. myeclipse 如何显示序号
  4. linux开发 stc_Linux下构建stc51单片机开发环境
  5. 1001.害死人不偿命的(3n+1)猜想
  6. 射频与微波测量之S参数
  7. 手机号段对应地区编码_漫画:“哈夫曼编码” 是什么鬼?
  8. 如何给IP Product找到可用的sales organization
  9. Web应用架构-Full-text Search Service
  10. C语言 函数不定长参数 ##__VA_ARGS__经典案例 - C语言零基础入门教程
  11. Android Camera (13)---MTK平台相机插值修改
  12. Kubernetes学习总结(17)—— Kubernetes 快速入门需要掌握的知识点总结
  13. Codeforces Round #320 (Div. 2) [Bayan Thanks-Round]
  14. LeetCode每日一题——串联字符串的最大长度
  15. 关于CAPWAP的一些概念
  16. 《Think Python》第15章学习笔记
  17. 出走的门徒之一——地平线 余凯:造物主的一小步
  18. 在线购物系统—类图设计
  19. html5 答题源码脚本,自动答题脚本教程及源码分享(无视分辨率)
  20. ​特拉华大学彭曦教授招收2021 Fall全奖博士生

热门文章

  1. 2021年月薪多少,才能在北上广深“体面”生活?
  2. php 身份证号码获取星座和生肖
  3. mutations的类型常量
  4. ECSHOP会员注册审核插件【会员注册审核登录】ECSHOP会员注册审核插件,会员注册审核通过登录
  5. Java高并发秒杀系统总结
  6. Ubuntu apparmor何方神圣
  7. 计算机辅助教学的弊端,浅谈多媒体辅助教学的利弊及对策
  8. 条码打印软件在条形码中设置多个变量的方法
  9. 三星Note3 S搜索功能如何使用
  10. 【JavaScript]实现动态拖拽小精灵