JAR 包冲突排雷指南:原理、现象与 Maven 一站式解决

一次诡异的 NoSuchMethodError,90 % 都是由同一个类在多个版本间反复横跳引起的。

一、为什么会冲突?

1.1 冲突产生的根因:同一个类在 classpath 中出现多次,且版本不同

以开篇例子为例:

  • a.jar → 引入 c.jar(version-1)
  • b.jar → 引入 c.jar(version-2)

项目运行时 "先到先得" 的类加载顺序导致:

加载顺序 结果
先加载 c-1 低版本类 ClassA 缺失 methodA()NoSuchMethodError
先加载 c-2 高版本向下兼容,一切正常

1.2 典型异常对照表

异常 含义
java.lang.ClassNotFoundException 版本里根本没有这个类
java.lang.NoSuchMethodError 版本里有类,但没有这个方法
java.lang.NoSuchFieldError 版本里有类,但没有这个字段
java.lang.LinkageError 类加载冲突导致链接失败

二、排查思路:三步定位法

Step 1:打印依赖树 ------ 用 Maven 做"CT 扫描"

bash 复制代码
mvn dependency:tree -Dverbose -Dincludes=:notify-common

输出示例(已高亮冲突):

复制代码
[INFO] +- com.taobao.wlb:bis-core:jar:1.0-SNAPSHOT
[INFO] |  \- com.taobao.logistics:schedule-client:1.1.1
[INFO] |     \- (com.taobao.notify:notify-common:1.8.15 - omitted for conflict with 1.8.19.26)
[INFO] \- com.taobao.notify:notify-tr-client:1.8.19.26
[INFO]    \- com.taobao.notify:notify-common:1.8.19.26
  • 冲突版本1.8.15 vs 1.8.19.26
  • 谁是引入者schedule-client:1.1.1 拉来了旧版本。

Step 2:运行时类加载详情 ------ JVM 的"X 光片"

启动参数加 -verbose:class,查看实际从哪个 JAR 加载:

复制代码
[Loaded com.xxx.ClassA from file:/.../c-1.0.jar]

Step 3:IDE 可视化 ------ 适合"肉眼"快速定位

  • Eclipse :打开 pom.xml → Hierarchy → 搜索冲突包
  • IDEApom.xml → Diagrams → Show Dependencies

三、解决手段:让"对的版本"留下来

3.1 排除旧版本(Maven)

找到引入冲突的坐标,在 pom.xml 中显式排除:

xml 复制代码
<dependency>
  <groupId>com.know.diamond</groupId>
  <artifactId>diamond-sdk</artifactId>
  <version>2.0.5</version>
  <exclusions>
    <exclusion>
      <groupId>com.google.collections</groupId>
      <artifactId>google-collections</artifactId>
    </exclusion>
  </exclusions>
</dependency>

3.2 统一版本:使用 dependencyManagement

xml 复制代码
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.taobao.notify</groupId>
      <artifactId>notify-common</artifactId>
      <version>1.8.19.26</version>
    </dependency>
  </dependencies>
</dependencyManagement>

3.3 全局分析:一次性导出完整树

bash 复制代码
mvn dependency:tree -Dverbose > tree.log

用文本编辑器搜索冲突 groupId:artifactId,快速定位所有叶子节点。


四、小结:一张图看懂排包流程

复制代码
┌────────────┐      ┌──────────────┐      ┌────────────────┐
│ NoSuchM··· │  →   │ dependency:  │  →   │ exclusion /    │
│ LinkageErr │      │ tree -Dverbose│      │ dependencyMgmt │
└────────────┘      └──────────────┘      └────────────────┘
        ↑                   ↑                     ↑
     运行报错           快速定位冲突            精准解决

一句话记住 :先 tree 找元凶,再 exclusion 干掉它,最后用 dependencyManagement 统一版本,冲突永不再现!