• MAVEN依赖的优先原则
  • 发布于 2个月前
  • 205 热度
    0 评论
Maven 依赖可以分为如下几部分:
直接依赖,就是本项目 dependencies 部分的依赖
间接依赖,就是本项目 dependencies 部分的依赖所包含的依赖
依赖管理,就是本项目 dependency management 里面的依赖
parent 的直接依赖
parent 的间接依赖
parent 的依赖管理
bom 的直接依赖(一般没有)
bom 的间接依赖(一般没有)
bom 的依赖管理
PS:bom 就是工程项目中最外层主 POM ,也就是 dependencyManagement 那个 POM

一、 MAVEN 依赖三大原则
1.1 最短路径优先原则
Maven 依赖遵循最短路径优先原则,当项目直接依赖一个 C-api-1.0 和 A-api-2.1 包,并且 C-api-1.0 有如下间接依赖关系:C-api-1.0 —> B-api-1.0 —> A-api-1.1 这时候项目里包含了 A-api 的 1.1 和 2.1 两个版本,由于存在最短路径原则明显 Project —> A-api-2.1 短于 Project —> C-api-1.0 —> B-api-1.0 —> A-api-1.1 故 Project 项目里会使用 A-api-2.1

示例项目中包含如下依赖
<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>3.10-FINAL</version>
    </dependency>

    <dependency>
      <artifactId>QLExpress</artifactId>
      <groupId>com.alibaba</groupId>
      <version>3.2.2</version>
    </dependency>

</dependencies>
其中 poi-ooxml 存在如下依赖关系:poi-ooxml-->poi-->commons-logging (版本 1.1 ) QLExpress 存在如下依赖关系:QLExpress —> commons-logging (版本 1.1.1 ) 由于存在最短路径原则,明显 QLExpress —> commons-logging 路径更短,项目会使用 commons-logging 的 1.1.1 版本

1.2 POM 文件中申明顺序优先原则

Maven 依赖遵循 POM 文件中申明顺序优先原则,当项目里存在直接依赖 C-api-1.0 和 B-api-1.0 其中存在如下间接依赖关系:C-api-1.0 —> A-api-2.1 B-api-1.0 —> A-api-1.1 这时项目间接依赖了 A-api 的 2.1 和 1.1 两个版本,由于存在 POM 文件中申明顺序优先原则,故项目中会使用 A-api-2.1

示例项目中存在如下依赖

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
  </dependency>


  <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.10-FINAL</version>
  </dependency>

  <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <version>3.17-beta1</version>
  </dependency>
</dependencies>
其中 poi-ooxml 依赖了包 poi ,poi-scratchpad 也依赖了 poi 包,但是 poi-ooxml 依赖了 poi 包的 3.10-FINAL 版本, poi-scratchpad 依赖了 poi 包的 3.17-beta1 版本,由于存在申明顺序优先原则,项目会使用 poi 包的 3.10-FINAL 版本图片

1.3 覆盖优先原则
Maven 依赖遵循覆盖优先原则,项目父 POM 中直接依赖包 A-api-1.1 ,子模块 Module A 的 parent 直接依赖了项目的 POM ,但是同时也直接依赖了 A-api-1.2 。由于存在覆盖优先原则子模块 Module A 中会优先使用 A-api-1.2 而不是父POM的 A-api-1.1图片在以上项目工程下,新建一个子工程,在子工程POM添加如下依赖
<dependencies>
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>5.2.3</version>
    </dependency>
</dependencies>
由于外部工程依赖了 poi 包的 3.10-FINAL ,但是子工程依赖了 poi 的 5.2.3 版本,故整体包依赖会包含poi的两个版本,但是在子工程中使用的是 5.2.3图片怎么证明我们在子工程使用的是 poi 的 5.2.3 版本呢?我们在子工程可以写一个 main 方法调用方法 org.apache.poi.util.Units 类的 columnWidthToEMU 方法,在父工程同样调用这个方法,发现父工程这个方法报错不存在。
import org.apache.poi.util.Units;
public class Test {
    // 堆代码 duidaima.com
    public static void main(String[] args) {
        Units.columnWidthToEMU(1);
    }

}
二、 MAVEN 依赖冲突常见报错
2.1 ClassNotFoundException
当项目启动时出现 ClassNotFoundException 这样的错误,表示由于项目使用的包版本下找不到当前需要的类 1、调用 class 的 forName 方法时,找不到指定的类。2、 ClassLoader 中的 findSystemClass() 方法时,找不到指定的类。3、 ClassLoader 中的 loadClass() 方法时,找不到指定的类。

2.2 NoSuchMethodError
NoSuchMethodError 就是程序在运行中找不到运行的方法导致的 1、有可能发生的就是 jar 冲突,可能是两个高低版本的 jar 包导致。2、有可能是有两个 jar 包有相同的类与方法,导致程序调用过程中找不到正确的方法。

三、Maven 依赖加载流程
Maven 依赖加载流程如下:
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 依赖的最短路径原则。可用文中 1.1 做示例如下:

四、总结
本次主要讲解了 maven 依赖包含的几大部分,以及 maven 依赖三大原则,并且对每种依赖原则都做了具体图解和示例,方便我们可以直接在项目中运行调试。期间对 maven 冲突导致的常见报错进行讲解方便我们在开发过程中快速定位问题。最后讲解了 maven 加载包进入项目中的整个流程,并按照文中 1.1 所讲的“最短路径优先原则“做为示例图解,进而加深对 maven 加载包流程的理解。
用户评论