<转载>解决jar包冲突新思路 - maven-shade-plugin
标签搜索
侧边栏壁纸
  • 累计撰写 18 篇文章
  • 累计收到 10 条评论

<转载>解决jar包冲突新思路 - maven-shade-plugin

Arlen
2024-01-10 / 0 评论 / 53 阅读 / 正在检测是否收录...

转载自知乎专栏:https://zhuanlan.zhihu.com/p/62796806

前言:
发生jar包冲突通常是因为,项目中依赖了同一个jar包的多个版本。一般的思路是只保留一个版本,删除掉不需要的版本。最近遇到了一个下图这样的例子:

排掉d1的话a会报错,排掉d2的话b会报错,所以希望在项目中同时使用d1和d2。

最开始同事说可以用maven-shade-plugin这个插件实现这个需求的时候,我的内心是这样的:

后来听他解释完以后才恍然大悟,感觉世界观再一次被刷新了,居然还有这种操作。。。下面就简单描述一下具体怎么用shade插件解决这个问题的吧。

正文:
首先介绍一下具体测试代码: (下载链接:package-test)

与前言中的图相对应,项目总共分3个模块:a\b\c,其中a和b分别依赖了guava的19.0(d1)和26.0.jre(d2),然后c同时引用了a和b。

其中guava的两个版本有下边两个不兼容的方法,用来测试:

public static Objects.ToStringHelper toStringHelper(Object self) {

    //该方法 19.0有,26.0.jre没有

}
public static String lenientFormat(

@Nullable String template, @Nullable Object @Nullable... args) {
    //该方法 19.0没有,26.0.jre有

}
直接执行com.zhaohui.C的main方法,会报如下错误:

Exception in thread "main" java.lang.NoSuchMethodError: com.google.common.base.Strings.lenientFormat(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
接下来就介绍一下解决问题的工具maven-shade-plugin。(源码地址:github) 这里使用3.2.1的tag。

为了更简单的了解maven-shade-plugin这个插件到底做了什么,可以直接打断点调试一下,跟着源码走一遍打包流程。

首先,下载源码,然后添加到package-test的module中,具体操作如下图:

然后package-test-c项目的pom文件增加这个插件:

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <transformers>
                        <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                            <mainClass>com.zhaohui.C</mainClass>
                        </transformer>
                    </transformers>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>


mvn插件的代码入口是@Mojo注解类的execute方法,在该方法入口(org.apache.maven.plugins.shade.mojo.ShadeMojo line385)打个断点,如下图:

最后一步按照下图操作:

增加一个run/debug configuration 最后点击debug按钮就可以调试了。具体生成jar包的代码org.apache.maven.plugins.shade.DefaultShader line151 shadeJars方法。

打断点发现,打包的时候,解析pom文件总共获取了4个jar包,其中guava只有19.0,没有26.0.jre,所以执行的时候才会报错找不到26.0.jre中的方法。

调试中,在org.apache.maven.plugins.shade.DefaultShader line539 有下面代码:

sourceContent = relocator.applyToSourceContent( sourceContent );
这个relocator会在打包过程中,修改类的包名。这个就是解决这个问题的关键。具体解决思路如下图:

在项目中新增一个模块b-shade,里边什么代码都没有,只有一个dependency b,然后配置maven-shade-plugin 如下:

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <relocations>
                            <relocation>
                                <pattern>com.google.common</pattern>
                                <shadedPattern>zhaohui.com.google.common</shadedPattern>
                            </relocation>
                        </relocations>
                    </configuration>
                </execution>
            </executions>

        </plugin>
    </plugins>
</build>

要求b-shade使用maven-shade-plugin打包,同时打包的时候规定将com.google.common包名改为zhaohui.com.google.common。

然后在c的pom文件中删除b的依赖,改为依赖b-shade.然后在根目录执行mvn package。

最后,在c的target目录中执行java -jar package-test-c-1.0-SNAPSHOT.jar,输出如下:

开始执行A的代码
Object{test=test}
A的代码,执行完了,没报错
开始执行A的代码
[java.lang.Object@330bedb4]
B的代码,执行完了,没报错
这样问题就圆满解决了。

最后的最后,使用luyten-0.5.3打开package-test-c-1.0-SNAPSHOT.jar,发现b中的import语句已经被修改为import zhaohui.com.google.common.base.*;

总结:
我只想说:新技能get√

最后,让我们保持独立思考,不卑不亢。长成自己想要的样子! (引用自 我非常喜欢的B站up主 ”独立菌儿“->猛戳链接<-的口头禅)

0

评论 (0)

取消