Maven依赖冲突排查实战|一文搞定Jar包地狱
项目跑着好好的,突然就NoSuchMethodError、ClassNotFoundException了。
十有八九是Maven依赖冲突。这篇分享我的排查经验。
一、依赖冲突是怎么产生的?
场景
项目依赖 A 1.0
项目依赖 B 2.0
A 1.0 依赖 C 1.0
B 2.0 依赖 C 2.0
Maven只会选一个版本的C,但A和B各自需要的版本不同,就可能出问题。
Maven的版本选择规则
- 最短路径优先:谁离项目近选谁
- 先声明优先:路径相同时,pom中先声明的优先
二、常见报错
NoSuchMethodError
java.lang.NoSuchMethodError: com.google.common.collect.ImmutableMap.of(...)
原因:运行时加载的类版本和编译时不一致。
ClassNotFoundException
java.lang.ClassNotFoundException: org.apache.commons.lang3.StringUtils
原因:依赖被排除了或者根本没引入。
NoClassDefFoundError
java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
原因:编译时有,运行时没有。
三、排查方法
3.1 查看依赖树
mvn dependency:tree
输出:
[INFO] com.example:my-app:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.7.0:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:2.7.0:compile
[INFO] | | +- org.springframework.boot:spring-boot:jar:2.7.0:compile
[INFO] | | \- org.springframework.boot:spring-boot-autoconfigure:jar:2.7.0:compile
3.2 搜索特定依赖
# 搜索guava相关依赖
mvn dependency:tree -Dincludes=com.google.guava
# 搜索多个
mvn dependency:tree -Dincludes=com.google.guava,org.slf4j
3.3 查看冲突详情
mvn dependency:tree -Dverbose
会显示被省略的依赖:
[INFO] +- com.example:lib-a:jar:1.0:compile
[INFO] | \- com.google.guava:guava:jar:30.0-jre:compile
[INFO] \- com.example:lib-b:jar:2.0:compile
[INFO] \- (com.google.guava:guava:jar:31.0-jre:compile - omitted for conflict with 30.0-jre)
3.4 分析依赖冲突
mvn dependency:analyze
输出:
[WARNING] Used undeclared dependencies found:
[WARNING] com.google.guava:guava:jar:30.0-jre:compile
[WARNING] Unused declared dependencies found:
[WARNING] org.apache.commons:commons-lang3:jar:3.12.0:compile
四、解决冲突
4.1 排除依赖
<dependency>
<groupId>com.example</groupId>
<artifactId>lib-a</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
4.2 强制指定版本
在项目中直接声明依赖,覆盖传递依赖:
<!-- 强制使用guava 31.0 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0-jre</version>
</dependency>
4.3 使用dependencyManagement
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0-jre</version>
</dependency>
</dependencies>
</dependencyManagement>
所有模块都会使用这个版本。
4.4 使用BOM(推荐)
<dependencyManagement>
<dependencies>
<!-- Spring Boot BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
五、常见冲突案例
5.1 SLF4J多绑定冲突
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/xxx/logback-classic-1.2.3.jar]
SLF4J: Found binding in [jar:file:/xxx/slf4j-log4j12-1.7.25.jar]
解决:排除多余的实现
<dependency>
<groupId>xxx</groupId>
<artifactId>xxx</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
5.2 Jackson版本冲突
com.fasterxml.jackson.databind.JsonMappingException:
Incompatible Jackson version: 2.10.0
解决:统一Jackson版本
<properties>
<jackson.version>2.15.0</jackson.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${jackson.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
5.3 Netty版本冲突
java.lang.NoSuchMethodError: io.netty.buffer.PooledByteBufAllocator
解决:使用Netty BOM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>4.1.100.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
六、IDEA插件辅助
Maven Helper插件
安装后在pom.xml底部有Dependency Analyzer标签:
- 红色:冲突的依赖
- 右键可以直接排除
直接跳转
按住Ctrl点击依赖,可以跳转到来源。
七、最佳实践
7.1 使用BOM管理版本
<dependencyManagement>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2023.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
7.2 定期检查依赖
# 检查依赖更新
mvn versions:display-dependency-updates
# 检查插件更新
mvn versions:display-plugin-updates
7.3 CI中加入依赖检查
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>enforce</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<dependencyConvergence/>
</rules>
</configuration>
</execution>
</executions>
</plugin>
有冲突时构建会失败。
八、远程调试依赖问题
有时候本地没问题,部署到服务器就报错,可能是服务器环境的依赖不同。
我用星空组网工具把本地和服务器连起来,直接SSH上去看:
# 查看实际加载的Jar包
ssh root@192.168.188.10
cd /app/lib
ls -la | grep guava
或者远程Debug看类加载:
# 启动时加参数
java -verbose:class -jar app.jar | grep guava
比跳板机方便,也能直接用本地IDE远程调试。
总结
依赖冲突排查流程:
1. mvn dependency:tree -Dincludes=xxx # 找到冲突
2. 确定需要的版本
3. exclusion排除 或 直接声明覆盖
4. mvn dependency:tree 验证
预防措施:
- 使用BOM管理版本
- maven-enforcer-plugin检查
- 定期更新依赖
有问题评论区交流~

浙公网安备 33010602011771号