只要没有重叠,将来自多个工件的类/资源聚合到一个 uber JAR 中是直接的。否则,需要某种逻辑来合并来自多个 JAR 的资源。这就是资源转换器发挥作用的地方。
ApacheLicenseResourceTransformer | 防止许可证重复 |
ApacheNoticeResourceTransformer | 准备合并通知 |
附加变压器 | 向资源添加内容 |
ComponentsXmlResourceTransformer | 聚合 Plexus components.xml |
DontIncludeResourceTransformer | 防止包含匹配资源 |
GroovyResourceTransformer | 合并 Apache Groovy 扩展模块 |
包括资源转换器 | 从项目中添加文件 |
清单资源转换器 | 在MANIFEST中设置条目 |
PluginXmlResourceTransformer | 聚合 Mavens plugin.xml |
ResourceBundleAppendingTransformer | 合并资源包 |
服务资源转换器 | 在META-INF/services资源中重新定位类名并将它们合并。 |
XmlAppendingTransformer | 将 XML 内容添加到 XML 资源 |
属性变压器 | 合并拥有序号的属性文件以解决冲突 |
OpenWebBeansPropertiesTransformer | 合并 Apache OpenWebBeans 配置文件 |
MicroprofileConfigTransformer | 基于序数合并冲突的 Microprofile Config 属性 |
针对 Plexus IoC 容器的组件的 JAR 包含一个META-INF/plexus/components.xml条目,用于声明组件及其要求。如果 uber JAR 聚合了多个 Plexus 组件,则需要使用ComponentsXmlResourceTransformer来合并 XML 描述符:
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ComponentsXmlResourceTransformer"/> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
从插件版本 1.3 开始,此资源转换器还将更新描述符以说明组件接口/实现(如果有)的重定位。
Plugin Tools 3.0引入了注解。现在对类的引用不再是类名作为字符串,而是实际的类引用。当您想重新定位类时,您必须手动维护META-INF/maven/plugin.xml,但现在可以使用PluginXmlResourceTransformer
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.PluginXmlResourceTransformer"/> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
提供某些接口实现的 JAR 文件通常附带一个META-INF/services/目录,该目录将接口映射到它们的实现类以供服务定位器查找。要重定位这些实现类的类名,并将同一接口的多个实现合并到一个服务条目中,可以使用ServicesResourceTransformer :
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
一些 jar 包含具有相同文件名的其他资源(例如属性文件)。为避免覆盖,您可以选择通过将其内容附加到一个文件中来合并它们。一个很好的例子是在聚合 spring-context 和 plexus-spring jar 时。它们都有META-INF/spring.handlers文件,Spring 使用该文件来处理 XML 模式命名空间。您可以使用AppendingTransformer合并具有该特定名称的所有文件的内容,如下所示:
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <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> ... </project>
对于 XML 文件,您可以改用XmlAppendingTransformer:
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer"> <resource>META-INF/magic.xml</resource> <!-- Add this to enable loading of DTDs <ignoreDtd>false</ignoreDtd> --> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
从插件版本 1.3.1 开始,XmlAppendingTransformer默认不加载 DTD,从而避免网络访问。这种模式的潜在缺点是无法解析外部实体,这可能会导致转换失败,例如在使用某些 JRE 1.4 中使用的 Crimson XML 解析器时。如果转换后的资源使用外部实体,则可以重新打开 DTD 解析,或者将对xerces:xercesImpl:2.9.1的插件依赖添加到 POM。
对于 ResourceBundles 属性文件,您可以使用ResourceBundleAppendingTransformer代替,这也将尊重所有可用的语言环境:
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ResourceBundleAppendingTransformer"> <!-- the base name of the resource bundle, a fully qualified class name --> <basename>path/to/Messages</basename> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
DontIncludeResourceTransformer允许在资源名称以给定值结尾时排除资源。
例如,以下示例排除了以.txt结尾的所有资源。
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer"> <resource>.txt</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
由于 maven-shade-plugin-3.0 还可以提供不应包含的资源列表,例如:
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer"> <resources> <resource>.txt</resource> <resource>READ.me</resource> </resources> </transformer>
IncludeResourceTransformer允许项目文件以给定名称包含在包中。
例如,以下示例在META-INF目录中将README.txt作为README包含在包中。
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer"> <resource>META-INF/README</resource> <file>README.txt</file> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
ManifestResourceTransformer允许替换MANIFEST中的现有条目并添加新条目。
例如以下样本集
默认情况下,ManifestResourceTransformer将重新定位以下属性:
使用附加属性,您也可以指定需要重定位的属性。
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <manifestEntries> <Main-Class>${app.main.class}</Main-Class> <X-Compile-Source-JDK>${maven.compile.source}</X-Compile-Source-JDK> <X-Compile-Target-JDK>${maven.compile.target}</X-Compile-Target-JDK> </manifestEntries> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
一些开源生产者(包括Apache 软件基金会)在 META-INF 目录中包含了他们的许可证副本。这些通常被命名为LICENSE或LICENSE.txt。在合并这些依赖项时,添加这些资源可能会造成混乱。ApacheLicenseResourceTransformer确保不会合并重复的许可证(根据此约定命名)。
例如,以下内容可防止将commons-collections依赖项中的许可证合并到
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer"> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
某些许可证(包括Apache 许可证,第 2 版)要求通知由下游分销商保留。ApacheNoticeResourceTransformer自动组装适当的NOTICE。
例如,简单地合并依赖通知:
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer"> <addHeader>false</addHeader> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
Apache Groovy 语言提供位于META-INF/services/org.codehaus.groovy.runtime.ExtensionModule 的扩展模块,这些模块使用属性文件格式。GroovyResourceTransformer自动组装 Groovy 扩展模块NOTICE。
比如简单合并几个jar的扩展模块:
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.GroovyResourceTransformer"> <extModuleName>the-aggregated-module</extModuleName> <extModuleVersion>1.0.0</extModuleVersion> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
PropertiesTransformer允许合并一组属性文件,并根据给定每个文件优先级的序数来解决冲突。可选的alreadyMergedKey允许在文件中具有布尔标志,如果设置为 true,则请求将文件用作合并的结果。如果两个文件在合并过程中被认为是完整的,那么阴影将失败。
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.properties.PropertiesTransformer"> <!-- required configuration --> <resource>configuration/application.properties</resource> <ordinalKey>ordinal</ordinalKey> <!-- optional configuration --> <alreadyMergedKey>already_merged</alreadyMergedKey> <defaultOrdinal>0</defaultOrdinal> <reverseOrder>false</reverseOrder> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
OpenWebBeansPropertiesTransformer为 Apache OpenWebBeans 配置文件预配置一个PropertiesTransformer 。
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.properties.OpenWebBeansPropertiesTransformer" /> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>
MicroprofileConfigTransformer为 Microprofile Config预配置一个PropertiesTransformer。唯一需要的配置是序数。支持 alreadyMergedKey但规范未定义。
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.4</version> <executions> <execution> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.properties.MicroprofileConfigTransformer"> <resource>configuration/app.properties</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> ... </project>