通过一些常见问题回顾Maven依赖中容易犯错的点
原文地址: http://andresalmiray.com/maven-dependencies-pop-quiz-results/
网上看到这篇文章,感觉很有价值,弄清了一些我之前理解错的点,这里翻译并分享下.
首先,先上一下我个人总结的结论:
Maven依赖可以分为如下几部分:
- 直接依赖,就是本项目 dependencies 部分的依赖
- 间接依赖,就是本项目 dependencies 部分的依赖所包含的依赖
- 依赖管理,就是本项目 dependency management 里面的依赖
- parent 的直接依赖
- parent 的间接依赖
- parent 的依赖管理
- bom 的直接依赖(一般没有)
- bom 的间接依赖(一般没有)
- bom 的依赖管理
可以这么理解依赖:
- 首先,将 parent 的直接依赖,间接依赖,还有依赖管理,插入本项目,放入本项目的直接依赖,间接依赖还有依赖管理之前
- 对于直接依赖,如果有 version,那么就依次放入 DependencyMap 中。如果没有 version,则从依赖管理中查出来 version,之后放入 DependencyMap 中。key 为依赖的 groupId + artifactId,value为version,后放入的会把之前放入的相同 key 的 value 替换
- 对于每个依赖,各自按照 1,2 加载自己的 pom 文件,但是如果第一步中的本项目 dependency management 中有依赖的版本,使用本项目 dependency management的依赖版本,生成 TransitiveDependencyMap,这里面就包含了所有的间接依赖。
- 所有间接依赖的 TransitiveDependencyMap, **对于项目的 DependencyMap 里面没有的 key,依次放入项目的 DependencyMap **
- 如果 TransitiveDependencyMap 里面还有间接依赖,那么递归执行3, 4。
由于是先放入本项目的 DependencyMap,再去递归 TransitiveDependencyMap,这就解释了 maven 依赖的最短路径原则。
Bom 的效果基本和 Parent 一样,只是一般限制中,Bom 只有 dependencyManagement 没有 dependencies
1. 简单项目依赖
1. 下面这个 maven 依赖,我们有两个一样的依赖,但是不同的版本,最后项目会依赖哪个版本呢?
答案是 28.2-jre,相同依赖不同版本,以最后的为准,根据最开始依赖载入步骤的第二步,依赖会被替换。
验证:
2. 下面这个 pom 文件中, Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,那么最后 guava 是哪个版本?
这个可能是我们经常会遇到的情况,例如对 netty 的依赖,如果你的项目使用了 Spring Cloud,RocketMQ,Redisson等,就会发现其实他们各自的netty依赖都不太一样。项目会以最短路径原则为准,决定依赖的版本。这里就是 guava 28.2-jre
验证:
3. 如果将 guava-27.0-jre 这个依赖放入 dependencyManagement 中,Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,那么最后 guava 是哪个版本?
非显示依赖,一切以 dependencyManagement 中的版本为准,可以参考最开始提到的步骤中的第三步。所以这里是 guava-27.0-jre
验证:
4. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
由于 dependencies 中有显式依赖,根据最开始我们提到的5步中可以看出,有显式依赖以这个依赖为准。所以答案是 guava-28.2-jre
验证:
5. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,guice 4.2.2 中有对于 guava 25.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,guice 和 Truth 会各自加载自己的依赖放入 TransitionDependencyMap,然后放入项目的 DependencyMap,已存在的 key 不会再次放入,所以谁先放入就是谁,这也是最短路径原则。这里就是 guice 的依赖优先,因为他在前面。答案是 guava-25.1-android
6. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,guice 4.2.2 中有对于 guava 25.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,间接依赖版本优先根据项目的 dependencyManagement,所以这里版本是 guava-28.2-jre
2. 有 parent 的项目
7. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,parent 的 dependencies 是直接加到本项目中,所以答案是 guava-28.2-jre
验证:
8. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,parent 的 dependencies 还有 dependencyManagement 是直接加到本项目中,并且 dependencies 是最优先的,所以答案是 guava-28.2-jre
验证:
9. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,parent 的 dependencyManagement 是直接加到本项目中,非显示依赖,一切以 dependencyManagement 中的版本为准,所以答案是guava-26.0-jre
验证:
10. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,parent 的 dependencyManagement 是直接加到本项目中,并且在本项目的前面,dependencyManagement 也是一个map,后面的替换前面的,所以dependencyManagement中的版本是28.2-jre,非显示依赖,一切以 dependencyManagement 中的版本为准,所以答案是guava-28.2-jre
验证:
3. 包含 bom 的项目
11. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,guice 4.2.2 中有对于 guava 25.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,bom 和 parent 一样,其中的 dependencyManagement 是直接加到本项目中,非显示依赖,一切以 dependencyManagement 中的版本为准,所以答案是guava-28.2-jre
验证:
12. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,bom 和 parent 一样, 其中的 dependencyManagement 还有 dependencies 是直接加到本项目中,并且在本项目的前面,根据最短路径原则,答案是guava-28.2-jre。
但是注意 一般标准的 bom 只有 dependencyManagement, 没有dependencies
验证:
13. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,bom 和 parent 一样, 其中的 dependencyManagement 是直接加到本项目中,并且在本项目的前面,,dependencyManagement 也是一个map,后面的替换前面的,所以dependencyManagement中的版本是28.2-jre,非显示依赖,一切以 dependencyManagement 中的版本为准,所以答案是guava-26.0-jre。
验证:
14. 下面这个项目中Truth 1.0这个依赖里面有对于 guava 27.0.1-android 的依赖,最后 guava 是哪个版本?
根据我之前总结的步骤,这个就很简单啦,最短路径原则,所以答案是guava-28.2-jre。
验证: