⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/u011709538/article/details/143034231 「战斧」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

之前我们讲解了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. \1. A —> C —> D —> E —> X(version 0.0.1)
  2. \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 来指定版本号

文章目录
  1. 1. 一、版本冲突的原因
  2. 2. 二、查看与分析冲突
    1. 2.0.1. 1. 依赖树
      1. 2.0.1.1. ① 原生命令
      2. 2.0.1.2. ② Maven Helper
    2. 2.0.2. 2. 冲突分析
      1. 2.0.2.1. ① 查看冲突
      2. 2.0.2.2. ② maven的版本规则
      3. 2.0.2.3. ③ 版本选择
  • 3. 三、maven解决版本冲突的方法
    1. 3.0.1. 1. 排除依赖
    2. 3.0.2. 2. 依赖管理
      1. 3.0.2.1. ① 单模块
      2. 3.0.2.2. ② 跨模块处理
  • 4. 四、结论