Maven|Maven 依赖调解源码解析(四)(传递依赖,第一声明者优先)

本文是系列文章《Maven 源码解析:依赖调解是如何实现的?》第四篇,主要介绍依赖调解的第二条原则:传递依赖,第一声明者优先。请按顺序阅读其他系列文章,系列文章总目录参见:https://www.cnblogs.com/xiaoxi666/p/15583241.html。
场景
路径最近者优先原则不能解决所有问题,比如这样的依赖关系:A-> C->X(1.0)、A->D->X(2.0),X(1.0)和 X(2.0)的依赖路径长度是一样的,都为 2。那么到底谁会被解析使用呢?在 Maven 2.0.8 及之前的版本中,这是不确定的,但是从 Maven 2.0.9 开始,为了尽可能避免构建的不确定性,Maven 定义了依赖调解的第二原则:第一声明者优先。在依赖路径长度相等的前提下,在 POM 中依赖声明的顺序决定了谁会被解析使用,顺序最靠前的那个依赖优胜。该例中,C 的依赖声明在 D 之前,那么 X(1.0)就会被解析使用。
B、C 、D 的 pom.xml 内容均不变。A 的 pom.xml 内容改动一下:

【Maven|Maven 依赖调解源码解析(四)(传递依赖,第一声明者优先)】mavenDependencyDemo org.example 1.0 4.0.0A 1.0 org.example C 1.0 org.example D 1.0

源码
和前面的分析方法一致,我们先执行 mvn dependency:tree -Dverbose 命令,看看输出:
[INFO] Scanning for projects... [INFO] [INFO] ---------------------------< org.example:A >---------------------------- [INFO] Building A 1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ A --- [INFO] org.example:A:jar:1.0 [INFO] +- org.example:C:jar:1.0:compile [INFO] |\- org.example:X:jar:1.0:compile [INFO] \- org.example:D:jar:1.0:compile [INFO]\- (org.example:X:jar:2.0:compile - omitted for conflict with 1.0) [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time:1.017 s [INFO] Finished at: 2021-11-20T15:52:36+08:00 [INFO] ------------------------------------------------------------------------

可以看出,A 依赖了 X(1.0),而 X(2.0)被忽略了。关键语句变成了
(org.example:X:jar:2.0:compile - omitted for conflict with 1.0)

看起来还是 omitted for conflict with 这个信息。基于前面的分析,很可能进入了这段代码:
Maven|Maven 依赖调解源码解析(四)(传递依赖,第一声明者优先)
文章图片

那自然而然,resolved 就是 X(1.0),我们直接进入源码分析:
Maven|Maven 依赖调解源码解析(四)(传递依赖,第一声明者优先)
文章图片

Maven|Maven 依赖调解源码解析(四)(传递依赖,第一声明者优先)
文章图片

很明显看出,如果两个依赖的路径深度相同,保留最先声明的依赖。
小结
有了前面的分析经验,这个原则的分析就很简单了,仍然是 NewestConflictResolver 进行调解。
这个「小于等于」就很有灵性。同时实现了两个原则。

    推荐阅读