[Maven] maven插件系列之maven-shade-plugin

1 插件简述/Plugin Overview

1.1 定义与目的/Definition & Goals

  • Official Definition

Apache Maven : maven-shade-plugin

This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies.(该插件提供了将工件打包到uber jar中的功能,包括其依赖项,并对一些依赖项的包进行着色(即重命名)。)

  • Goals Overview

The Shade Plugin has a single goal: (Shade插件只有一个目标:)

shade:shade is bound to the package phase and is used to create a shaded jar. (shade:shade绑定到封装阶段,用于创建一个shaded jar。)

  • Sample Explain/简单解释:

maven-plugin-shade 插件提供了2个能力:

把整个项目(包含它的依赖)都打包到一个 “uber-jar” 中 shade - 即重命名某些依赖的包。也由此引出了两个问题:

+ 什么是 uber-jar ?

+ 这中打包后带依赖的 Jar 包一般称为 uber-jar 或 fat-jar 或者 jar-with-dependencies;意思就是包含依赖的 jar。

+ 什么是 shade ?

+ shade 意为遮挡,在此处可理解为:对依赖的 jar 包的重定向(主要通过重命名的方式)。

shade
n. 灯罩;阴凉处;(树)荫;色度;痕迹,影子,遗风;一点;差别;背阴;暗部;阴魂;浓淡深浅
vt. 给…遮挡(光线);画阴影;加灯罩;把…涂暗;险胜 uber
adj.超级的;极其的;最好的;

1.2 Version/版本

If you like to use minimizeJar this means you have to use JDK8+. This is based on a required upgrade of dependencies.

如果你喜欢使用minimizeJar,这意味着你必须使用JDK8+。这是基于所需的依赖项升级。

Latest version(最新版本) = 3.5.0

https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-shade-plugin

2 实践与使用/Usage

2.1 官方插件说明

Official Document/官方文档

General instructions on how to use the Shade Plugin can be found on the usage page. Some more specific use cases are described in the examples given below.
有关如何使用Shade插件的一般说明可以在使用页面上找到。下面给出的示例中描述了一些更具体的用例。 In case you still have questions regarding the plugin's usage, please feel free to contact the user mailing list. The posts to the mailing list are archived and could already contain the answer to your question as part of an older thread. Hence, it is also worth browsing/searching the mail archive.
如果您对插件的使用仍有疑问,请随时联系用户邮件列表。邮件列表中的帖子已存档,可能已经包含了您问题的答案,作为旧线程的一部分。因此,浏览/搜索邮件档案也是值得的。 If you feel like the plugin is missing a feature or has a defect, you can fill a feature request or bug report in our issue tracker. When creating a new issue, please provide a comprehensive description of your concern. Especially for fixing bugs it is crucial that the developers can reproduce your problem. For this reason, entire debug logs, POMs or most preferably little demo projects attached to the issue are very much appreciated. Of course, patches are welcome, too. Contributors can check out the project from our source repository and will find supplementary information in the guide to helping with Maven.
如果你觉得插件缺少功能或有缺陷,你可以在我们的问题跟踪器中填写功能请求或错误报告。创建新问题时,请对您关心的问题进行全面描述。特别是对于修复错误,开发人员能够重现您的问题是至关重要的。出于这个原因,非常感谢整个调试日志、POM,或者最好是附加到该问题的小演示项目。当然,补丁也是受欢迎的。参与者可以从我们的源代码库中查看该项目,并在帮助使用Maven的指南中找到补充信息。

2.2 基本使用 : build>plugin

2.2.0 maven-shade-plguin 的基本使用

  • maven-plugin-shade 必须和 Maven 构建生命周期中的 package 阶段绑定。

也就是说,当执行 mvn package 时会自动触发 shade

  • 要使用 maven-shade-plugin,只需要在 pom.xml<plugins> 标签下添加它的配置即可,示例如下:
<project>
//... <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<configuration>
<!-- 此处按需编写更具体的配置 -->
</configuration>
<executions>
<execution>
<!-- 和 package 阶段绑定 -->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> // ...
</project>

默认情况下,会把项目所有的依赖都包含进最终的 jar 包中。当然,我们也可在 <configuration> 标签内配置更具体的规则。

2.2.1 测试验证(maven-shade-plugin)

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--
<parent>
<artifactId>johnny-webapp-quickstart</artifactId>
<groupId>cn.johnnyzen</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
-->
<modelVersion>4.0.0</modelVersion> <version>1.0.0-SNAPSHOT</version>
<groupId>cn.johnnyzen</groupId>
<artifactId>study-maven</artifactId> <properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven-shade-plugin.version>3.5.0</maven-shade-plugin.version> <fastjson.version>2.0.3</fastjson.version>
</properties> <dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<configuration>
<!-- 此处按需编写更具体的配置 -->
</configuration>
<executions>
<execution>
<!-- 和 package 阶段绑定 -->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
  • 打包结果
mvn clean install

2.2.2 测试验证(maven-compile-plugin)

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--
<parent>
<artifactId>johnny-webapp-quickstart</artifactId>
<groupId>cn.johnnyzen</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
-->
<modelVersion>4.0.0</modelVersion> <version>1.0.0-SNAPSHOT</version>
<groupId>cn.johnnyzen</groupId>
<artifactId>study-maven</artifactId> <properties>
<java.jdk.version>1.8</java.jdk.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven-shade-plugin.version>3.5.0</maven-shade-plugin.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<fastjson.version>2.0.3</fastjson.version>
</properties> <dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.jdk.version}</source>
<target>${java.jdk.version}</target>
<!--<encoding>${project.build.outputEncoding}</encoding>-->
<!-- <skipTests>true</skipTests> --><!-- 跳过测试 -->
<!--<verbose>true</verbose>--> <!--<showWarnings>true</showWarnings>--> <!--<fork>true</fork>--><!-- 要使compilerVersion标签生效,还需要将fork设为true,用于明确表示编译版本配置的可用 -->
<!--<executable>--><!-- path-to-javac --><!--</executable>--><!-- 使用指定的javac命令,例如:<executable>${JAVA_1_4_HOME}/bin/javac</executable> -->
<!--<compilerVersion>${java.version}</compilerVersion>--><!-- 指定插件将使用的编译器的版本 -->
<!--<meminitial>128m</meminitial>--><!-- 编译器使用的初始内存 -->
<!--<maxmem>512m</maxmem>--><!-- 编译器使用的最大内存 -->
<!--<compilerArgument>-verbose -bootclasspath ${java.home}\lib\rt.jar</compilerArgument>--><!-- 这个选项用来传递编译器自身不包含但是却支持的参数选项 -->
</configuration>
</plugin>
</plugins>
</build>
</project>
  • 打包效果
mvn clean install

2.2.3 测试验证(build is empty)

  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<!--
<parent>
<artifactId>johnny-webapp-quickstart</artifactId>
<groupId>cn.johnnyzen</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
-->
<modelVersion>4.0.0</modelVersion> <version>1.0.0-SNAPSHOT</version>
<groupId>cn.johnnyzen</groupId>
<artifactId>study-maven</artifactId> <properties>
<java.jdk.version>1.8</java.jdk.version>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven-shade-plugin.version>3.5.0</maven-shade-plugin.version>
<maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
<fastjson.version>2.0.3</fastjson.version>
</properties> <dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
</dependencies> <build>
</build>
</project>
  • 打包效果
mvn clean install

2.3 扩展配置: build>plugin>configuration

2.3.1 include/exclude : 按需选择要添加到最终 jar 包中依赖

  • 支持include/exclude 2 种操作
  • 支持执行通配符匹配目标依赖JAR包: '*' 、'?'
  • 配置格式:
groupId:artifactId[[:type]:classfier]
  • 样例配置
<configuration>
<artifactSet>
<excludes>
<exclude>classworlds:classworlds</exclude>
<exclude>junit:junit</exclude>
<exclude>jmock:*</exclude>
<exclude>*:xml-apis</exclude>
<exclude>org.apache.maven:lib:tests</exclude>
<exclude>log4j:log4j:jar:</exclude>
</excludes>
</artifactSet>
</configuration>

2.3.2 filter : 过滤

  • 使用 <filters> 结合 <includes> & <excludes> 标签可实现更灵活的依赖选择。
  • 样例配置:
<configuration>
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/framework/**</include>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/experimental/**</exclude>
<exclude>org/junit/runners/**</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>

2.3.3 minimizeJar : 最小化JAR包体积

  • 除了可以通过自定义的 filters 来过滤依赖,此插件还支持自动移除项目中没有使用到的依赖,以此来最小化 jar 包的体积,只需要添加一项配置即可。示例如下:
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>

2.3.4 relocations : 重定位 class 文件

如果最终的 jar 包被其他的项目所依赖的话,直接地引用此 jar 包中的类可能会导致类加载冲突,这是因为 classpath 中可能存在重复的 class 文件。为了解决这个问题,我们可以使用 shade 提供的重定位功能,把部分类移动到一个全新的包中。示例如下:

<configuration>
<relocations>
<relocation>
<pattern>org.codehaus.plexus.util</pattern>
<shadedPattern>org.shaded.plexus.util</shadedPattern>
<excludes>
<exclude>org.codehaus.plexus.util.xml.Xpp3Dom</exclude>
<exclude>org.codehaus.plexus.util.xml.pull.*</exclude>
</excludes>
</relocation>
</relocations>
</configuration>
涉及标签:
<pattern>:原始包名
<shadedPattern>:重命名后的包名
<excludes>:原始包内不需要重定位的类,类名支持通配符 例如,在上述示例中,我们把 org.codehaus.plexus.util 包内的所有子包及 class 文件(除了 ~.xml.Xpp3Dom 和 ~.xml.pull 包下的所有 class 文件)重定位到了 org.shaded.plexus.util 包内。

当然,如果包内的大部分类我们都不需要,一个个排除就显得很繁琐了。

此时我们也可以使用 <includes> 标签来指定我们仅需要的类,示例如下:

<project>
...
<relocation>
<pattern>org.codehaus.plexus.util</pattern>
<shadedPattern>org.shaded.plexus.util</shadedPattern>
<includes>
<include>org.codehaud.plexus.util.io.*</include>
</includes>
</relocation>
...
</project>

2.3.5 mainClass:生成可执行 jar 包

  • 使用 maven-shade-plugin 后,最终生成的 jar 包可以包含所有项目所需要的依赖。

    我们会想,能不能直接运行这个 uber-jar 呢?答案是当然可以,并且十分简单,只需要指定 <mainClass> 启动类就可以了。
  • 示例如下:
<project>
...
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.sonatype.haven.HavenCli</mainClass>
</transformer>
</transformers>
</configuration>
...
</project>

熟悉 jar 包的朋友们都知道,jar 包中默认会包含一个 MANIFEST.MF 文件,里面描述了一些 jar 包的信息

使用 java 自带的 jar 命令打包的时候可以指定 MANIFEST.MF,其中也可以指定 Main-Class 来使得 jar 包可运行。

那么使用 shade 来指定和直接在 MANIFEST.MF 文件中指定有什么区别呢?

答案是没有区别,细心的读者会发现 <mainClass> 标签的父标签是 <transformer> 有一个 implementation 属性,其值为 “~.ManifestResourceTransformer”,意思是 Manifest 资源文件转换器。

上述示例只自指定了启动类,因此 shade 会为我们自动生成一个包含 Main-Class 的 MANIFEST.MF 文件,然后在打 jar 包时指定这个文件。

那如果我们想要完全定制 MANIFEST.MF 文件内容怎么办呢?我们可以使用 <manifestEntries> 标签,示例如下:

<project>
...
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>org.sonatype.haven.ExodusCli</Main-Class>
<Build-Number>123</Build-Number>
</manifestEntries>
</transformer>
</transformers>
</configuration>
...
</project>

可执行jar包通过 java  -jar  命令启动

2.3.6 生成资源文件

项目中涉及到的依赖可能会有它们所必需的资源文件,使用 shade 可以把它们聚合在同一个 jar 包中。

默认地,shade 为我们提供了 12 个 ResourceTransformer 类:

类名 作用
ApacheLicenseResourceTransformer 防止 LICENSE 文件重复
ApacheNoticeResourceTransformer 准备合并的 NOTICE
AppendingTransformer 为某个资源文件附加内容
ComponentsXmlResourceTransformer 聚合 Plexus components.xml
DontIncludeResourceTransformer 防止包含指定的资源
GroovyResourceTransformer 合并 Apache Groovy 的扩展模块
IncludeResourceTransformer 添加项目中的文件为资源文件
ManifestResourceTransformer 自定义 MANIFEST 文件
PluginXmlResourceTransformer 聚合 Maven 的 plugin.xml 配置
ResourceBundleAppendingTransformer 合并 ResourceBundles
ServicesResourceTransformer 重定位且合并 META-INF/services 资源文件中的 class 文件
XmlAppendingTransformer 为 XML 资源文件附加内容

如果上述 12 个类都不能够满足我们的需求,我们可以实现 shade 提供的接口,按需自定义一个 ResourceTransformer,实现方法详见官网 Using your own Shader implementation。

X 参考文献/Reference Document

[Maven] maven插件系列之maven-shade-plugin的更多相关文章

  1. maven添加插件,与maven打包

    1.编译插件 添加编译器插件来告诉 Maven 使用哪个 JDK 版本是用来编译项目. 2.pom <plugin> <groupId>org.apache.maven.plu ...

  2. maven的学习系列(二)—maven的文件夹结构

    maven的文件有自己的组织方式,例如以下所看到的: ---maven ----src ---main ----java ---test ----java -----pom.xml 当运行完mvn c ...

  3. Maven 默认插件以及功能

    Maven 默认插件 已知 Maven 使用 plugin 来执行实际操作的,在默认情况下,Maven 会绑定以下几个插件来完成基本操作. plugin function life cycle pha ...

  4. 【maven】插件和依赖管理

    1.插件管理 定义 pluginManagement 用来做插件管理的.它是表示插件声明,即你在项目中的pluginManagement下声明了插件,Maven不会加载该插件,pluginManage ...

  5. IntelliJ IDEA(九) :酷炫插件系列

    最近项目比较忙,很久没有更新IDEA系列了,今天介绍一下IDEA的一些炫酷的插件,IDEA强大的插件库,不仅能给我们带来一些开发的便捷,还能提高我们的与众不同. 1.插件的安装 打开setting文件 ...

  6. IntelliJ IDEA插件系列

    参考: IntelliJ IDEA插件系列 1. activate-power-mode 和 Power mode II 根据Atom的插件activate-power-mode的效果移植到IDEA上 ...

  7. Maven提高篇系列之(六)——编写自己的Plugin(本系列完)

    这是一个Maven提高篇的系列,包含有以下文章: Maven提高篇系列之(一)——多模块 vs 继承 Maven提高篇系列之(二)——配置Plugin到某个Phase(以Selenium集成测试为例) ...

  8. [Apache Maven Shade Plugin] [example] [001] 官方例子:includes-excludes

    链接地址:[Selecting Contents for Uber JAR](http://maven.apache.org/plugins/maven-shade-plugin/examples/i ...

  9. 施用 maven shade plugin 解决 jar 或类的多版本冲突

    施用 maven shade plugin 解决 jar 或类的多版本冲突   使用 maven shade plugin 解决 jar 或类的多版本冲突java 应用经常会碰到的依赖的三方库出现版本 ...

  10. Maven系列(一)plugin

    Maven系列(一)plugin maven-compiler-plugin 使用 mvn compile 命令,出现错误: 编码 GBK 的不可映射字符而不能编译.这是因为代码或注释中存在中文引起的 ...

随机推荐

  1. 聊聊Cola-StateMachine轻量级状态机的实现

    背景 在分析Seata的saga模式实现时,实在是被其复杂的 json 状态语言定义文件劝退,我是有点没想明白为啥要用这么来实现状态机:盲猜可能是基于可视化的状态机设计器来定制化流程,更方便快捷且上手 ...

  2. 眼观四海:自动驾驶&4D成像毫米波雷达 如今几何?

    写在前面 笔者做这项工作的目的是希望为课题组寻找毫米波雷达+智慧驾驶领域寻找可行的趋势与方向,尽可能贴近工业界需求.在这项工作中,笔者总结了以多级联(大陆,博世,森斯泰克等).集成芯片(Arbe,Mo ...

  3. java接口返回图片链接或pdf链接如何设置在线预览还是下载

    之前文章说到了如何通过将文件转成图片或者pdf来实现在线预览,一般来说在线预览图片或者pdf都是存储在图片服务器上的,在通过接口调用把文件返回给前端,但是把文件返回给前端效果一般是有两种:在线预览和下 ...

  4. 痞子衡嵌入式:主流QuadSPI NOR Flash厂商关于QE位与IO功能复用关联设计

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家讲的是几家主流QuadSPI NOR Flash厂商关于QE位与IO功能复用关联设计. 痞子衡之前写过一篇文章 <串行NOR Flash下 ...

  5. Java发展历程及各版本新特性

    Java的历史是非常有意思的.1990年底,Sun Microsystems在工作站计算机市场上领先世界,并继续保持健康发展.Sun想把本公司的创新和专业知识应用到即将到来的消费电子市场领域,于是该公 ...

  6. 尚医通day16-网站怎么接入微信扫码支付?

    第01章-准备工作 1.微信支付产品介绍 参考资料:产品中心 - 微信支付商户平台 (qq.com) 付款码支付.JSAPI支付.小程序支付.Native支付.APP支付.刷脸支付 1.1.付款码支付 ...

  7. Transformer算法的应用

    目录 1. 引言 2. 技术原理及概念 2.1. 基本概念解释 2.2. 技术原理介绍 2.3. 相关技术比较 3. 实现步骤与流程 3.1. 准备工作:环境配置与依赖安装 3.2. 核心模块实现 4 ...

  8. 工作中必备的12个Git命令

    前言 以下是工作中必备的12个Git命令,包括创建和初始化仓库.克隆远程仓库.添加和提交文件.查看状态和历史记录.创建和切换分支.合并分支以及推送和拉取远程仓库等操作.掌握这些命令可以帮助你进行基本的 ...

  9. EtherCAT 转CCLINK网关连接三菱plc应用案例

    EtherCAT 现场总线协议是由德国倍福公司在 2003 年提出的,该通讯协议拓扑结构十分灵活,数据传输速度快,同步特性好,可以形成各种网络拓扑结构. 捷米特JM-ECT-CCLK  是自主研发的一 ...

  10. PerfView专题 (第十三篇):洞察 .NET程序 的非托管句柄泄露

    一:背景 1. 讲故事 前几天写了一篇 如何洞察 .NET程序 非托管句柄泄露 的文章,文中使用 WinDbg 的 !htrace 命令实现了句柄泄露的洞察,在文末我也说了,WinDbg 是以侵入式的 ...