如何使用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




