You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Apache Maven Shade插件解决多版本依赖冲突问题

如何使用Apache Maven Shade插件解决多版本依赖冲突问题

嘿,这个多版本Guava依赖冲突的问题确实挺棘手的,我来给你捋捋怎么用Maven Shade插件搞定它~

核心思路其实很简单:把每个版本的Guava都重命名成完全独立的包路径,让它们在打包后的Jar里互不干扰,同时修改第三方依赖的字节码,让它们指向对应的重命名版本。具体操作分两步:

第一步:明确引入所有需要的Guava版本并排除第三方依赖自带的Guava

首先得让Maven别自动帮你“选”某个Guava版本,而是把每个第三方依赖需要的版本都明确引入,同时排除掉第三方依赖自带的Guava,避免依赖调解干扰。

在你的pom.xml<dependencies>里这么配置:

<dependencies>
  <!-- 第三方依赖1:排除它自带的Guava31 -->
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>thirdparty-1</artifactId>
    <version>x.y.z</version>
    <exclusions>
      <exclusion>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
      </exclusion>
    </exclusions>
  </dependency>

  <!-- 专门给thirdparty-1用的Guava31 -->
  <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
    <scope>compile</scope>
  </dependency>

  <!-- 第三方依赖2:排除它自带的Guava18 -->
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>thirdparty-2</artifactId>
    <version>a.b.c</version>
    <exclusions>
      <exclusion>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
      </exclusion>
    </exclusions>
  </dependency>

  <!-- 专门给thirdparty-2用的Guava18 -->
  <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
    <scope>compile</scope>
  </dependency>

  <!-- 第三方依赖3:排除它自带的Guava4 -->
  <dependency>
    <groupId>com.example</groupId>
    <artifactId>thirdparty-3</artifactId>
    <version>m.n.o</version>
    <exclusions>
      <exclusion>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
      </exclusion>
    </exclusions>
  </dependency>

  <!-- 专门给thirdparty-3用的Guava4 -->
  <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>4.0</version>
    <scope>compile</scope>
  </dependency>
</dependencies>

第二步:配置Shade插件,对每个Guava版本单独重命名

接下来在Shade插件里,给每个版本的Guava设置独立的重命名规则,让它们变成不同的包路径,同时指定每个规则只作用于对应版本的Guava artifact。

pom.xml<build>里添加插件配置:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.4.1</version> <!-- 选一个稳定的最新版本 -->
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
          <configuration>
            <relocations>
              <!-- 把Guava31重命名到com.myproject.guava31 -->
              <relocation>
                <pattern>com.google.guava</pattern>
                <shadedPattern>com.myproject.guava31</shadedPattern>
                <includes>
                  <include>com.google.guava:guava:31.0.1-jre</include>
                </includes>
              </relocation>

              <!-- 把Guava18重命名到com.myproject.guava18 -->
              <relocation>
                <pattern>com.google.guava</pattern>
                <shadedPattern>com.myproject.guava18</shadedPattern>
                <includes>
                  <include>com.google.guava:guava:18.0</include>
                </includes>
              </relocation>

              <!-- 把Guava4重命名到com.myproject.guava4 -->
              <relocation>
                <pattern>com.google.guava</pattern>
                <shadedPattern>com.myproject.guava4</shadedPattern>
                <includes>
                  <include>com.google.guava:guava:4.0</include>
                </includes>
              </relocation>
            </relocations>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

原理和注意事项

  • 原理:Shade插件会修改第三方依赖的字节码,把它们对com.google.guava的引用替换成对应的重命名路径(比如thirdparty-1的引用会变成com.myproject.guava31),同时把每个版本的Guava打包到对应的路径下,这样三个版本完全独立,不会冲突。
  • 注意点1:一定要确保每个第三方依赖都排除了自带的Guava,不然Maven的依赖调解机制可能会覆盖掉某些版本,导致打包不全。
  • 注意点2:最终的Jar包会变大,因为包含了多个版本的Guava,这是为了兼容不同第三方依赖的必要代价。
  • 注意点3:如果第三方依赖还依赖Guava的子模块(比如guava-collections),记得也要给这些子模块做同样的重命名配置。

备注:内容来源于stack exchange,提问作者Kane.Sun

火山引擎 最新活动