Maven版本冲突的原因分析和解决指南

 更新时间:2025年11月09日 08:30:11   作者:皮皮林551  
我们可能会因为Maven功能变更、性能提升、修复漏洞等多种原因,去更换第三方库或框架,此时就容易发生版本冲突,本期我们就介绍一下相关知识,以及如何解决版本冲突方法,需要的朋友可以参考下

之前我们讲解了Maven的配置,那么这次我们就讲讲一些更贴近日常维护的东西,就是maven的版本控制,在一个工程的正常生命周期内。

我们可能会因为功能变更、性能提升、修复漏洞等多种原因,去更换第三方库或框架。此时就容易发生版本冲突,本期我们就介绍一下相关知识,以及如何解决版本冲突。

一、版本冲突的原因

内部冲突:  当一个项目直接依赖了不同的版本号,可能会导致冲突。

模块间冲突:  一个库内部不同模块之间使用了不同的版本号,或互相引用时,也可能导致冲突。

二、查看与分析冲突

1. 依赖树

① 原生命令

使用dependency:tree命令查看依赖树:maven提供了一个命令mvn dependency:tree,可以查看项目的依赖树,从而帮助我们分析版本冲突的原因。例如:

mvn dependency:tree

运行上述命令,maven会打印出项目的依赖树,我们可以根据这个依赖树找到冲突的版本并解决它。

② Maven Helper

原生命令的可视化成都有限,所以对于开发者来说,最常用的还是在IDEA上安装maven helper插件了,我们可以在IDEA插件市场里将其安装上

安装并启用成功后,我们打开某pom文件,就能看到该pom下的依赖情况了

2. 冲突分析

① 查看冲突

在安装完Maven Helper后, 我们其实可以直接看到有哪些冲突,如下图,项目上就存在如下的jar包冲突,当我们选中poi-oomxl后,右边则具体显示了造成该冲突的具体情况

不难看出,项目中用了多个不同的组件,而这些组件又使用了不同版本的 poi-oomxl,最终导致在项目中引用了三个不同版本的 poi-oomxl

② maven的版本规则

不难看出,尽管项目中依赖了三个不同的版本,但最后我们实际在项目中存在的却只会有一个 poi-oomxl 组件。那么在发生冲突时,maven 到底会取用哪个版本的组件呢?这就涉及到maven的版本规则

就近原则(最短路径)

多条路径时,选择最短的路径(依赖的层级小),如下,就会选用第二条路径,最后选择的版本为 version 0.0.2

  1. A —> C —> D —> E —> X(version 0.0.1)
  2. A —> F —> X(version 0.0.2)

声明顺序

在路径相同的情况下,Maven会选择最先声明的版本。如下,就会选用第一条路径,最后选择的版本为 version 0.0.1

  1. A —> C —> X(version 0.0.1)
  2. A —> F —> X(version 0.0.2)

我们来看一个例子,这里maven为我们选择了4.1.2,就是因为我们直接在pom文件里指定了版本4.1.2,所以它就只有一层,是最短路径。

如果我们把pom里的直接引用内容注释掉

那么就会用新的最短路径了,最终选取的版本为4.1.1

③ 版本选择

一般来说,我们相信组件都具有“向下兼容”的能力,即低版本组件的功能,在高版本上应该也能使用。所以当出现组件冲突时,我们往往选择保留目前的最高版本。

三、maven解决版本冲突的方法

1. 排除依赖

当我们发现某个依赖引起了冲突,可以使用 maven 的exclude标签排除它。例如:

<dependencies>
    <dependency>
        <groupId>example.group</groupId>
        <artifactId>example.artifact</artifactId>
        <version>1.0</version>
        <!-- <exclusions> 元素用于排除指定的依赖 -->
        <exclusions>
            <exclusion>
                <groupId>conflict.group</groupId>
                <artifactId>conflict.artifact</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

上述代码中,假如 example.artifact 引用了某个版本的 conflict.artifact ,与其他地方引用的conflict.artifact 发生冲突,我们就可以这样,把example.artifact 里的 conflict.artifact 剔除掉。如果是使用插件的话,则更方便,右键选中组件,即可以快速进行 exclude

2. 依赖管理

但是使用 exclusions 也有比较麻烦的地方,exclusions 只对当前依赖有效,并不会影响其他依赖。因此,如果项目中有多个依赖引入了相同的冲突依赖,需要在每个依赖中都使用 exclusions 元素进行排除。所以,有时候我们希望明确指定某个依赖的版本号,可以使用maven的dependencyManagement标签来达到目的

① 单模块

如下 在pom文件中,我们加入dependencyManagement,并在其中指定了poi-ooxml的版本号为4.1.2(注意dependencyManagement只有管理信息的功能,并没有真实引用poi-ooxml,所以后面的引用段落仍然要保留)

然后在引用的段落里,把版本号清除掉

此时我们再去看引用情况,就会发现所有的引用全部变成了 4.1.2,不再有冲突提示

② 跨模块处理

多模块的管理,更加需要使用 dependencyManagement 来确保各子模块在使用相同版本的组件。所以此时需要在父POM文件中加入dependencyManagement

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>parent-project</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
       <module>../child1</module>
       <module>../child2</module>
       <module>../child3</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.1.2</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

然后在所有子模块的pom文件里只保留引用,不再指定版本号,如下

<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
    </dependency>
</dependencies>

此时,所有子模块凡是引用了poi-ooxml的, 就都会指定使用 4.1.2 版本,而不会再产生冲突了。当然,如果某个子项目需要指定一个特殊的版本号时,只需要在自己项目的pom.xml中显示声明一个版本号即可,因为就近原则的关系,该模块会使用自己指定的版本号

四、结论

在软件开发过程中,版本冲突是一个常见的问题。我们本次就了解maven在发生版本冲突时,该如何查看冲突情况,并知道maven选择哪个版本是遵循就近原则、与声明顺序的。而在处理时我们可以使用排包(exclusive)法,或者显示的使用 dependencyManagement 来指定版本号。

以上就是Maven版本冲突的原因分析和解决指南的详细内容,更多关于Maven版本冲突解决的资料请关注脚本之家其它相关文章!

相关文章

  • Java数据结构之实现哈希表的分离链接法

    Java数据结构之实现哈希表的分离链接法

    今天给大家带来的是关于Java数据结构的相关知识,文章围绕着Java哈希表的分离链接法展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Java MyBatis本地缓存原理详解

    Java MyBatis本地缓存原理详解

    这篇文章主要介绍了Java MyBatis本地缓存原理详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-07-07
  • Java使用备忘录模式实现过关类游戏功能详解

    Java使用备忘录模式实现过关类游戏功能详解

    这篇文章主要介绍了Java使用备忘录模式实现过关类游戏功能,结合实例形式详细分析了java备忘录模式的概念、原理及其在过关类游戏中的具体应用方法,需要的朋友可以参考下
    2018-04-04
  • SpringBoot配置动态数据源的实战详解

    SpringBoot配置动态数据源的实战详解

    Spring对数据源的管理类似于策略模式,不懂策略模式也没关系,其实就是有一个全局的键值对,类型是Map<String, DataSource>,当JDBC操作数据库之时,会根据不同的key值选择不同的数据源,本文介绍了SpringBoot配置动态数据源的方法,需要的朋友可以参考下
    2024-08-08
  • SpringBoot如何配置MySQL和Oracl双数据源(Mybatis)

    SpringBoot如何配置MySQL和Oracl双数据源(Mybatis)

    这篇文章主要介绍了SpringBoot如何配置MySQL和Oracl双数据源(Mybatis)问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • SpringBoot+Netty实现简单聊天室的示例代码

    SpringBoot+Netty实现简单聊天室的示例代码

    这篇文章主要介绍了如何利用SpringBoot Netty实现简单聊天室,文中的示例代码讲解详细,对我们学习SpringBoot有一定帮助,感兴趣的同学可以了解一下
    2022-02-02
  • Springboot @RequestBody注解踩坑记录

    Springboot @RequestBody注解踩坑记录

    这篇文章主要介绍了Springboot @RequestBody注解踩坑记录,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java实现数据库连接池的方法

    Java实现数据库连接池的方法

    这篇文章主要介绍了Java实现数据库连接池的方法,涉及java数据库连接池的创建、连接、刷新、关闭及状态获取的常用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • Java基本数据类型与封装类型详解(int和Integer区别)

    Java基本数据类型与封装类型详解(int和Integer区别)

    这篇文章主要介绍了Java基本数据类型与封装类型详解(int和Integer区别) ,需要的朋友可以参考下
    2017-02-02
  • Java中的MapStruct的使用方法代码实例

    Java中的MapStruct的使用方法代码实例

    这篇文章主要介绍了Java中的MapStruct的使用方法代码实例,mapstruct是一种实体类映射框架,能够通过Java注解将一个实体类的属性安全地赋值给另一个实体类,有了mapstruct,只需要定义一个映射器接口,声明需要映射的方法,需要的朋友可以参考下
    2023-10-10

最新评论