Maven依赖冲突排查实战|一文搞定Jar包地狱

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 排除依赖

com.example

lib-a

1.0

com.google.guava

guava

4.2 强制指定版本

在项目中直接声明依赖,覆盖传递依赖:

com.google.guava

guava

31.0-jre

4.3 使用dependencyManagement

com.google.guava

guava

31.0-jre

所有模块都会使用这个版本。

4.4 使用BOM(推荐)

org.springframework.boot

spring-boot-dependencies

3.2.0

pom

import

五、常见冲突案例

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]

解决:排除多余的实现

xxx

xxx

org.slf4j

slf4j-log4j12

5.2 Jackson版本冲突

com.fasterxml.jackson.databind.JsonMappingException:

Incompatible Jackson version: 2.10.0

解决:统一Jackson版本

2.15.0

com.fasterxml.jackson

jackson-bom

${jackson.version}

pom

import

5.3 Netty版本冲突

java.lang.NoSuchMethodError: io.netty.buffer.PooledByteBufAllocator

解决:使用Netty BOM

io.netty

netty-bom

4.1.100.Final

pom

import

六、IDEA插件辅助

Maven Helper插件

安装后在pom.xml底部有Dependency Analyzer标签:

红色:冲突的依赖

右键可以直接排除

直接跳转

按住Ctrl点击依赖,可以跳转到来源。

七、最佳实践

7.1 使用BOM管理版本

org.springframework.boot

spring-boot-dependencies

3.2.0

pom

import

org.springframework.cloud

spring-cloud-dependencies

2023.0.0

pom

import

7.2 定期检查依赖

# 检查依赖更新

mvn versions:display-dependency-updates

# 检查插件更新

mvn versions:display-plugin-updates

7.3 CI中加入依赖检查

org.apache.maven.plugins

maven-enforcer-plugin

3.4.1

enforce

enforce

有冲突时构建会失败。

八、远程调试依赖问题

有时候本地没问题,部署到服务器就报错,可能是服务器环境的依赖不同。

我用星空组网工具把本地和服务器连起来,直接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检查

定期更新依赖

有问题评论区交流~

相关推荐

同花顺上怎么开股票账户,自己点击开户就可以吗
怎么查自己农村合作医疗交了没有?
股票里的钱多久到账 到账时间详解