一文详解Maven中依赖冲突的正确处理方法

 更新时间:2025年12月02日 08:58:40   作者:踏浪无痕  
Maven依赖冲突是 Java 开发中的常见问题,很多人遇到后习惯到处写 exclusion,本文将从 JSqlParser 版本冲突的真实案例出发,讲清楚 Maven 的依赖仲裁机制,感兴趣的小伙伴可以了解下

事情是这样的

前几天遇到一个线上问题,SQL 解析直接超时了,日志里一堆 JSQLParserException: Time out occurred。排查下来发现是 JSqlParser 4.6 版本的一个已知 bug,解析复杂 SQL 的时候会陷入回溯地狱,CPU 直接打满。

解决方案很简单,升级到 4.9 就好了。但问题来了——我们项目里有好几个库都依赖 JSqlParser:

  • mybatis-plus-core 依赖 4.6
  • pagehelper 依赖 4.6
  • 我们自己的 flcloud-jdbc-cipher 要用 4.9

这就尴尬了,同一个 jar 包,三个地方要三个版本,Maven 怎么处理?

Maven 的依赖仲裁机制

先说结论:Maven 不会真的引入多个版本,最终只会保留一个

那它怎么决定保留哪个?规则其实挺简单的:

举个例子,假设依赖树是这样的:

三个 jsqlparser,深度分别是 4 层、3 层、2 层。按"路径最短优先",4.9 胜出。

但实际情况往往没这么简单,深度可能差不多,这时候就看谁在 pom 里写在前面了。

我当时的第一反应:到处写 exclusion

说实话,我一开始的想法就是简单粗暴,把不想要的版本排除掉:

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
    <exclusions>
        <exclusion>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>2.1.0</version>
    <exclusions>
        <exclusion>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
        </exclusion>
    </exclusions>
</dependency>

能用是能用,但问题也很明显:

  • 要改好几个地方,容易漏
  • 新同事不知道这段历史,可能哪天又加了个依赖把 4.6 带进来
  • 看着就难受,到处都是 exclusion

后来发现更优雅的方式

其实 Maven 早就提供了统一管理依赖版本的机制:在父 pom 的 dependencyManagement 里锁版本

<!-- 父 pom.xml -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>4.9</version>
        </dependency>
    </dependencies>
</dependencyManagement>

就这么简单。加上这段之后,不管子模块的依赖树里 jsqlparser 出现多少次、原本写的是什么版本,最终都会被统一成 4.9。

改完之后跑一下 mvn dependency:tree | grep jsqlparser,确认只剩一个版本就行了。

为什么 dependencyManagement 优先级最高

这块我之前也没太搞明白,后来翻了下 Maven 的文档,大概是这么个优先级顺序:

dependencyManagement 的作用就是"预定义"版本号,它不会真的引入依赖,但一旦这个依赖在依赖树中出现,就会强制使用预定义的版本。

所以它的优先级比什么路径深度、声明顺序都高,直接一锤定音。

几个要注意的地方

验证是必须的

改完版本之后,别急着提交,先验证一下各个库在新版本下能不能正常工作。jsqlparser 4.7 之后有些 API 变了,比如 SubSelectSelectBody 这些类被 干掉了。如果哪个库用到了这些老 API,启动的时候就会报 NoSuchMethodError

我们这次还好,mybatis-plus 和 pagehelper 用的都是比较基础的 API,升到 4.9 之后跑了下单测,没啥问题。

查看依赖树的命令

# 看完整依赖树
mvn dependency:tree

# 只看某个依赖
mvn dependency:tree | grep jsqlparser

# 更详细的冲突分析
mvn dependency:tree -Dverbose -Dincludes=com.github.jsqlparser:jsqlparser

IDEA 也能看

如果你用 IDEA,pom 文件底部有个 "Dependency Analyzer" 标签页,能看到依赖树和冲突情况,比命令行直观多了。

总结一下

说白了就是:能用 dependencyManagement 解决的,就别到处写 exclusion

前者是"我说了算",后者是"我不要这个不要那个"。心态都不一样。

到此这篇关于一文详解Maven中依赖冲突的正确处理方法的文章就介绍到这了,更多相关Maven依赖冲突内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java实现字符串转String数组的方法示例

    java实现字符串转String数组的方法示例

    这篇文章主要介绍了java实现字符串转String数组的方法,涉及java字符串的遍历、分割、转换等相关操作技巧,需要的朋友可以参考下
    2017-10-10
  • Java日常练习题,每天进步一点点(10)

    Java日常练习题,每天进步一点点(10)

    下面小编就为大家带来一篇Java基础的几道练习题(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望可以帮到你
    2021-07-07
  • Java虚拟机JVM类加载机制(从类文件到虚拟机)

    Java虚拟机JVM类加载机制(从类文件到虚拟机)

    所谓的类加载机制就是虚拟机将class文件加载到内存,并对数据进行验证,转换解析和初始化,形成虚拟机可以直接使用的java类型,本文给大家介绍类加载机制过程从类文件到虚拟机的详细说明,感兴趣的朋友跟随小编一起看看吧
    2021-06-06
  • redis客户端Jedis使用小结

    redis客户端Jedis使用小结

    Jedis是Redis的一款Java语言的开源客户端连接工具,本文主要介绍了redis客户端Jedis使用,具有一定的参考价值,感兴趣的可以了解一下
    2023-11-11
  • 解决ApplicationContext获取不到Bean的问题

    解决ApplicationContext获取不到Bean的问题

    这篇文章主要介绍了解决ApplicationContext获取不到Bean的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • Java ffmpeg 实现视频加文字/图片水印功能(示例代码)

    Java ffmpeg 实现视频加文字/图片水印功能(示例代码)

    本文介绍了使用Java和ffmpeg库实现视频加文字或图片水印的方法,通过引入依赖代码和示例,详细说明了如何将文字水印和图片水印添加到视频中,为需要在视频中加入水印的开发者提供了实用的指导,这种方法不仅增强了视频内容的版权保护,也为视频编辑提供了更多的可能性
    2024-10-10
  • SpringCloud2020整合Nacos-Bootstrap配置不生效的解决

    SpringCloud2020整合Nacos-Bootstrap配置不生效的解决

    这篇文章主要介绍了SpringCloud2020整合Nacos-Bootstrap配置不生效的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • springboot打包JAR包瘦身lib和配置文件分离方式

    springboot打包JAR包瘦身lib和配置文件分离方式

    本文介绍了如何通过优化POM.xml配置来减小JAR包大小,提高传输速度,主要步骤包括:指定打包环境和跳过编译单元测试、JAR打包排除配置文件和lib、提供全量包便于开发环境使用、将lib和配置文件单独复制出来
    2024-11-11
  • java自定义Scanner类似功能类的实例讲解

    java自定义Scanner类似功能类的实例讲解

    这篇文章主要介绍了java自定义Scanner类似功能类的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • java中List集合及其遍历详解

    java中List集合及其遍历详解

    这篇文章主要介绍了java中List集合及其遍历详解的相关资料,需要的朋友可以参考下
    2015-07-07

最新评论