Maven-Shade-Plugin必知必会

问题背景

工作项目使用了hadoop-common的jar包,其中内置了protobuf-java 2.5.0版本。

1
2
3
[INFO] +- org.apache.hadoop:hadoop-common:jar:2.6.0-cdh5.11.0:compile
[INFO] | +- org.apache.hadoop:hadoop-annotations:jar:2.6.0-cdh5.11.0:compile
[INFO] | +- com.google.protobuf:protobuf-java:jar:2.5.0:compile

而新加入的Calcite-core的jar包中内置了protobuf-java 3.1.0版本。

1
2
3
4
[INFO] +- org.apache.calcite:calcite-core:jar:1.13.0:compile
[INFO] | +- org.apache.calcite.avatica:avatica-core:jar:1.10.0:compile
[INFO] | | +- org.apache.calcite.avatica:avatica-metrics:jar:1.10.0:compile
[INFO] | | +- com.google.protobuf:protobuf-java:jar:3.1.0:compile

如果这两个版本的jar包能够向下兼容的话,我只需要exclude掉2.6.0的jar包就可以手工了。
然而自己实践了一把之后,发现如果exclude 2.6.0的protobuf会导致hbase初始化异常,而exclude 3.1.0的jar包会导致Calcite-core could not found function **这种低版本报错。

这种情况下就需要两个版本的jar包并存,那怎么解决这个冲突问题呢?

解决方法

  1. maven-shade-plugin
    使用maven-shade-plugin的relocate功能,可以将内部依赖的包换成另外一个别名,如下代码所示,可以将名空间com.google.protobuf转换成shaded.com.google.protobuf

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.4.1</version>
    <configuration>
    <createDependencyReducedPom>false</createDependencyReducedPom>
    </configuration>
    <executions>
    <execution>
    <phase>package</phase>
    <goals>
    <goal>shade</goal>
    </goals>
    <configuration>
    <filters>
    <filter>
    <artifact>*:*</artifact>
    <excludes>
    <exclude>META-INF/*.SF</exclude>
    <exclude>META-INF/*.DSA</exclude>
    <exclude>META-INF/*.RSA</exclude>
    </excludes>
    </filter>
    </filters>
    <relocations>
    <relocation>
    <pattern>com.google.protobuf</pattern>
    <shadedPattern>shaded.com.google.protobuf</shadedPattern>
    </relocation>
    </relocations>
    </configuration>
    </execution>
    </executions>
    </plugin>
  2. 注意maven-shade-plugin的版本,需要3.0+才能生效
    stackoverflow传送门

  3. 因为在shade的过程中,文件位置重新变过,所以也需要更新META-INF中的内容,shade plugin也提供这样的转换,传送

    1
    2
    3
    <transformers>
    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
    </transformers>

Shade Plugin进阶

需求

Maven项目提供的Shade插件,能够将Maven应用打包为超级的uber-jar(也成为fat jar,或shaded jar)。在打包过程中可以

  • 包含依赖库
  • 重命名依赖库的包名(以避免类库的冲突)
  • 有选择的打包

介绍

Shade插件目前最近版本是3.1.0

  1. 默认作用阶段为Package, 执行目标为shade
  2. pom文件配置方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
    <!-- put your configurations here -->
    </configuration>
    <executions>
    <execution>
    <phase>package</phase>
    <goals>
    <goal>shade</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
  3. 修改部分依赖的包名(避免冲突)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.1.0</version>
    <configuration>
    <relocations>
    <relocation>
    <pattern>com.google.protobuf</pattern>
    <shadedPattern>shaded.com.google.protobuf</shadedPattern>
    </relocation>
    </relocations>
    </configuration>
    <executions>
    <execution>
    <phase>package</phase>
    <goals>
    <goal>shade</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
  4. 资源转换器, Shade插件提供了多种资源转换器,资源转换器-传送门
    需要资源转换器,是因为Aggregating classes/resources from several artifacts into one uber JAR is straight forward as long as there is no overlap. Otherwise, some kind of logic to merge resources from several JARs is required. This is where resource transformers kick in.

  5. 执行package命令mvn clean package,会在target文件夹下生成一个uber-jar,以-shaded.jar为后缀的jar包。

Gifts of roses, hand a fragrance