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

项目跑着好好的,突然就NoSuchMethodErrorClassNotFoundException了。

十有八九是Maven依赖冲突。这篇分享我的排查经验。


一、依赖冲突是怎么产生的?

场景



项目依赖 A 1.0
项目依赖 B 2.0
A 1.0 依赖 C 1.0
B 2.0 依赖 C 2.0

Maven只会选一个版本的C,但A和B各自需要的版本不同,就可能出问题。

Maven的版本选择规则

  1. 最短路径优先:谁离项目近选谁
  2. 先声明优先:路径相同时,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检查
  • 定期更新依赖

有问题评论区交流~


posted @ 2025-12-08 09:29  花宝宝  阅读(77)  评论(0)    收藏  举报