通过一些常见问题回顾Maven依赖中容易犯错的点

原文地址: http://andresalmiray.com/maven-dependencies-pop-quiz-results/

网上看到这篇文章,感觉很有价值,弄清了一些我之前理解错的点,这里翻译并分享下.

首先,先上一下我个人总结的结论

Maven依赖可以分为如下几部分:

  1. 直接依赖,就是本项目 dependencies 部分的依赖
  2. 间接依赖,就是本项目 dependencies 部分的依赖所包含的依赖
  3. 依赖管理,就是本项目 dependency management 里面的依赖
  4. parent 的直接依赖
  5. parent 的间接依赖
  6. parent 的依赖管理
  7. bom 的直接依赖(一般没有)
  8. bom 的间接依赖(一般没有)
  9. bom 的依赖管理

可以这么理解依赖:

  1. 首先,将 parent 的直接依赖,间接依赖,还有依赖管理,插入本项目,放入本项目的直接依赖,间接依赖还有依赖管理之前
  2. 对于直接依赖,如果有 version,那么就依次放入 DependencyMap 中。如果没有 version,则从依赖管理中查出来 version,之后放入 DependencyMap 中。key 为依赖的 groupId + artifactId,value为version,后放入的会把之前放入的相同 key 的 value 替换
  3. 对于每个依赖,各自按照 1,2 加载自己的 pom 文件,但是如果第一步中的本项目 dependency management 中有依赖的版本,使用本项目 dependency management的依赖版本,生成 TransitiveDependencyMap,这里面就包含了所有的间接依赖。
  4. 所有间接依赖的 TransitiveDependencyMap, **对于项目的 DependencyMap 里面没有的 key,依次放入项目的 DependencyMap **
  5. 如果 TransitiveDependencyMap 里面还有间接依赖,那么递归执行3, 4。

由于是先放入本项目的 DependencyMap,再去递归 TransitiveDependencyMap,这就解释了 maven 依赖的最短路径原则。

Bom 的效果基本和 Parent 一样,只是一般限制中,Bom 只有 dependencyManagement 没有 dependencies

1. 简单项目依赖

1. 下面这个 maven 依赖,我们有两个一样的依赖,但是不同的版本,最后项目会依赖哪个版本呢?通过一些常见问题回顾Maven依赖中容易犯错的点
答案是 28.2-jre,相同依赖不同版本,以最后的为准,根据最开始依赖载入步骤的第二步,依赖会被替换。

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

2. 下面这个 pom 文件中, Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,那么最后 guava 是哪个版本?

通过一些常见问题回顾Maven依赖中容易犯错的点

这个可能是我们经常会遇到的情况,例如对 netty 的依赖,如果你的项目使用了 Spring Cloud,RocketMQ,Redisson等,就会发现其实他们各自的netty依赖都不太一样。项目会以最短路径原则为准,决定依赖的版本。这里就是 guava 28.2-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

3. 如果将 guava-27.0-jre 这个依赖放入 dependencyManagement 中,Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,那么最后 guava 是哪个版本?

通过一些常见问题回顾Maven依赖中容易犯错的点

非显示依赖,一切以 dependencyManagement 中的版本为准,可以参考最开始提到的步骤中的第三步。所以这里是 guava-27.0-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

4. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
通过一些常见问题回顾Maven依赖中容易犯错的点
由于 dependencies 中有显式依赖,根据最开始我们提到的5步中可以看出,有显式依赖以这个依赖为准。所以答案是 guava-28.2-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

5. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,guice 4.2.2 中有对于 guava 25.1-android 的依赖,最后 guava 是哪个版本?
通过一些常见问题回顾Maven依赖中容易犯错的点
根据我之前总结的步骤,guice 和 Truth 会各自加载自己的依赖放入 TransitionDependencyMap,然后放入项目的 DependencyMap,已存在的 key 不会再次放入,所以谁先放入就是谁,这也是最短路径原则。这里就是 guice 的依赖优先,因为他在前面。答案是 guava-25.1-android
通过一些常见问题回顾Maven依赖中容易犯错的点

6. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,guice 4.2.2 中有对于 guava 25.1-android 的依赖,最后 guava 是哪个版本?
通过一些常见问题回顾Maven依赖中容易犯错的点
根据我之前总结的步骤,间接依赖版本优先根据项目的 dependencyManagement,所以这里版本是 guava-28.2-jre
通过一些常见问题回顾Maven依赖中容易犯错的点

2. 有 parent 的项目

7. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
通过一些常见问题回顾Maven依赖中容易犯错的点

根据我之前总结的步骤,parent 的 dependencies 是直接加到本项目中,所以答案是 guava-28.2-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

8. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?

通过一些常见问题回顾Maven依赖中容易犯错的点
根据我之前总结的步骤,parent 的 dependencies 还有 dependencyManagement 是直接加到本项目中,并且 dependencies 是最优先的,所以答案是 guava-28.2-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

9. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
通过一些常见问题回顾Maven依赖中容易犯错的点

根据我之前总结的步骤,parent 的 dependencyManagement 是直接加到本项目中,非显示依赖,一切以 dependencyManagement 中的版本为准,所以答案是guava-26.0-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

10. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?

通过一些常见问题回顾Maven依赖中容易犯错的点

根据我之前总结的步骤,parent 的 dependencyManagement 是直接加到本项目中,并且在本项目的前面,dependencyManagement 也是一个map,后面的替换前面的,所以dependencyManagement中的版本是28.2-jre,非显示依赖,一切以 dependencyManagement 中的版本为准,所以答案是guava-28.2-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

3. 包含 bom 的项目

11. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,guice 4.2.2 中有对于 guava 25.1-android 的依赖,最后 guava 是哪个版本?

通过一些常见问题回顾Maven依赖中容易犯错的点

根据我之前总结的步骤,bom 和 parent 一样,其中的 dependencyManagement 是直接加到本项目中,非显示依赖,一切以 dependencyManagement 中的版本为准,所以答案是guava-28.2-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

12. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?

通过一些常见问题回顾Maven依赖中容易犯错的点

根据我之前总结的步骤,bom 和 parent 一样, 其中的 dependencyManagement 还有 dependencies 是直接加到本项目中,并且在本项目的前面,根据最短路径原则,答案是guava-28.2-jre

但是注意 一般标准的 bom 只有 dependencyManagement, 没有dependencies

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

13. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?

通过一些常见问题回顾Maven依赖中容易犯错的点

根据我之前总结的步骤,bom 和 parent 一样, 其中的 dependencyManagement 是直接加到本项目中,并且在本项目的前面,,dependencyManagement 也是一个map,后面的替换前面的,所以dependencyManagement中的版本是28.2-jre,非显示依赖,一切以 dependencyManagement 中的版本为准,所以答案是guava-26.0-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点

14. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?

通过一些常见问题回顾Maven依赖中容易犯错的点

根据我之前总结的步骤,这个就很简单啦,最短路径原则,所以答案是guava-28.2-jre

验证:
通过一些常见问题回顾Maven依赖中容易犯错的点