只要没有重叠,将来自多个工件的类/资源聚合到一个 uber JAR 中是直接的。否则,需要某种逻辑来合并来自多个 JAR 的资源。这就是资源转换器发挥作用的地方。
针对 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>1.4</version>
<executions>
<execution>
<phase>package</phase>
<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 开始,此资源转换器还将更新描述符以说明组件接口/实现(如果有)的重定位。
提供某些接口实现的 JAR 文件通常附带一个META-INF/services/目录,该目录将接口映射到它们的实现类以供服务定位器查找。要将同一接口的多个实现合并到一个服务条目中,可以使用ServicesResourceTransformer :
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<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>1.4</version>
<executions>
<execution>
<phase>package</phase>
<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>1.4</version>
<executions>
<execution>
<phase>package</phase>
<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。