maven依赖管理

2022年 3月 29日 48点热度 0人点赞

依赖传递

maven 的依赖, 可以形象的展示为一颗树, 每一个节点都可以引入更多的依赖节点. 那么当依赖树引入了一个包的多个版本, maven 如何决定使用哪一个版本呢? 原理很简单: 最短路径.

如何理解最短路径?

  • 层级越少的, 优先级越高.
  • 同一层级的, 越靠前, 优先级越高.

例如下图中, 依赖 A 的优先级为 A1>A2>A3>A4, B 的优先级为 B1>B2.

Maven 默认处理策略

最短路径优先

Maven 面对 D1 和 D2 时, 会默认选择最短路径的那个 jar 包, 即 D2.E->F->D2 比 A->B->C->D1 路径短 1.

最先声明优先

如果路径一样的话, 举个例子: A->B->C1, E->F->C2, 两个依赖路径长度都是 2, 那么就选择最先声明.

  • 在第一级, 谁后声明, 使用谁:
  • 不在第一级, 谁先声明, 使用谁:
  • 依赖最短路径优先原则: 一个项目依赖了两个 jar 包, 其中 A -> B -> C ->X(1.0) , A -> D -> X(2.0). 由于 X(2.0) 路径最短, 所以项目使用的是 X(2.0).
  • pom 文件中申明顺序优先: 如果 A -> B -> X(1.0) , A -> C -> X(2.0) 这样的路径长度一样怎么办呢? 这样的情况下, maven 会根据 pom 文件声明的顺序加载, 如果先声明了 B, 后声明了 C, 那最后的依赖就会是 X(1.0).
  • 覆写优先: 子 pom 内声明的优先于父 pom 中的依赖.

原文链接:https://blog.csdn.net/qq_42799615/article/details/105585427

如果按照最短路径优先, 路径相同则最先声明的优先的原则, 那么"同一个文件中后声明的优先级比先声明的高"则会看上去矛盾, 这位老哥的 Maven 源码 debug 给我解答了这个问题.

xiaoxi666 说: 从源码可以看到, 如果在同一个 pom 文件内, 声明了两个 groupId 和 artifactId 完全相同的依赖, 则会以最后一个声明的依赖为准. 因为在实现层面, 它们是保存在 Map 中的, 后一个依赖会把前一个依赖覆盖掉. 这也印证了该原则的名称: 同一个文件内声明, 后者覆盖前者.

相关博客链接:

[系列文章]Maven 源码解析: 依赖调解是如何实现的?
系列文章目录 (请务必按照顺序阅读):

依赖关系

Maven 定义了几种依赖关系, 分别是 compile, test, runtime, provided 和 system:

scope 说明 示例
compile 编译时需要用到该 jar 包 (默认) commons-logging
test 编译 Test 时需要用到该 jar 包 junit
runtime 编译时不需要, 但运行时需要用到 mysql
provided 编译时需要用到, 但运行时由 JDK 或某个服务器提供 servlet-api

如果不显式设置 <scope> 属性时, 默认 <scope>compile</scope>.

Maven 将通过遍历依赖关系图找到所有的依赖关系, 并且构建该应用程序.

可传递性依赖发现

一种相当常见的情况, 比如说 A 依赖于其他库 B. 如果另外一个项目 C 想要使用 A, 那么 C 项目也需要使用库 B.

Maven 可以避免去搜索所有所需库的需求. Maven 通过读取项目文件 (pom.xml), 找出它们项目之间的依赖关系.

我们需要做的只是在每个项目的 pom 中定义好直接的依赖关系, 其他的事情 Maven 会帮我们搞定.

命令

mvn dependency:help
mvn dependency:analyze
mvn dependency:tree
mvn dependency:tree -Dverbose

依赖管理解决什么问题

当同一个工程内有多个模块时, 并且要求多个模块使用某个 jar 包的相同版本, 为了方便统一版本号, 升级版本号, 需要提取出一个父亲模块来管理子模块共同依赖的 jar 包版本.

dependencyManagement 的作用有两个:

  • 指定使用某个依赖的哪一个版本
  • 统一管理版本

在 dependencyManagement 指定版本号后, 在与 dependencyManagement 同级的, dependencies 标签里面, 引入依赖时, 就可以不指定版本号了.

最佳实践

  • 项目中源代码使用的 jar 包一定在 pom.xml 中显式引用.
  • 经常 check 一下包冲突, 检查是否需要处理.
  • 当使用多个模块时, parent 一定要使用包管理模块来规范 Jar 包版本, 而不是包依赖模块直接引入依赖

rainbow

这个人很懒,什么都没留下

文章评论