只要没有重叠,将来自多个工件的类/资源聚合到一个 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.3.3</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.3.3</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.3.3</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.3.3</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。