Maven的依赖传递

Maven的依赖传递是指,当一个项目依赖于另外一个项目时,Maven会自动将被依赖项目的依赖库也加入到当前项目的依赖库中。这样,我们就可以在当前项目中直接使用被依赖项目的依赖库,而不需要手动声明它们。

一、关键pom文件

1.1 super pom

  super pom是Maven中所有pom.xml文件的默认父pom.xml文件,它定义了所有Maven项目都会继承的默认配置信息。当我们创建一个新的Maven项目时,如果没有指定父pom.xml文件,Maven会自动将super pom作为父pom.xml文件。这类似于Java创建类时都会默认继承Object类。

super pom的内容包含了一些默认的配置信息,例如:

  • groupId:默认值为org.apache.maven。
  • artifactId:默认值为maven-model。
  • version:默认值为Maven的版本号。
  • packaging:默认值为jar。
  • dependencies:包含了一些常用的依赖库,例如JUnit、Log4j等。
  • build:包含了一些常用的构建插件,例如Maven Compiler Plugin、Maven Surefire Plugin等。

  Maven的安装目录中的$M2_HOME/lib/maven-model-builder-*.jar文件来查看super pom的内容。在这个jar包中,有一个super-pom.xml文件,就是Maven的默认super pom。

  可以通过修改super pom来修改所有Maven项目的默认配置信息。但是,建议不要修改super pom,而是通过在pom.xml文件中声明<dependencyManagement>元素来管理依赖库的版本号,以及通过在pom.xml文件中声明<pluginManagement>元素来管理构建插件的配置信息。

1.2 effective pom

  Maven在处理pom.xml文件时,将所有继承关系、依赖关系、插件配置等信息合并后生成的最终pom.xml文件。这个最终的pom.xml文件包含了所有继承自父pom.xml文件的配置信息,以及所有依赖库的版本号、依赖范围等信息。

  可以通过Maven命令mvn help:effective-pom来查看当前项目的effective pom。执行该命令后,Maven会将当前项目的所有配置信息打印到控制台上,包括所有继承自父pom.xml文件的配置信息,以及所有依赖库的版本号、依赖范围等信息。

二、依赖范围

Maven中的依赖范围(scope)用来控制依赖库在不同阶段的使用范围。Maven中定义了以下几种依赖范围:

  • compile:默认的依赖范围,表示依赖库在编译、测试、运行时都可用。
  • provided:表示依赖库在编译和测试时可用,但在运行时不可用,因为它会由JDK或容器提供。
  • runtime:表示依赖库在测试和运行时可用,但在编译时不可用。
  • test:表示依赖库只在测试时可用,不会被打包到最终的应用程序中。
  • system:表示依赖库在编译和测试时可用,但不会从Maven仓库中下载,需要手动指定路径。
  • import:表示依赖库的作用类似于<dependencyManagement>元素,用来管理依赖库的版本号。

  在pom.xml文件中,我们可以使用<scope>元素来声明依赖库的范围,例如JUnit测试相关的依赖范围是<scope>runtime</scope>,合理使用依赖范围可以避免不必要的依赖库加载,减少应用程序的体积,提高应用程序的性能。

三、依赖调节

随着项目工程层级和所需依赖的增加,依赖树也在不断膨胀,为了简化依赖和让开发者尽可能只关心直接依赖,同时在一个间接依赖存在多个引入路径时不会出现依赖重复的问题,Maven的依赖调节遵循以下两条原则:

  1. 引入路径短者优先
  2. 先声明者优先

以上两条原则,优先使用第一条原则解决,第一条原则无法解决,再使用第二条原则解决。

3.1 引入路径短者优先

当一个间接依赖存在多条引入路径时,引入路径短的会被解析使用。

例如,A 存在这样的依赖关系:
依赖1:A->B->C->D(1.0)
依赖2:A->X->D(2.0)

D是A的间接依赖,存在两个版本的D,依赖1的路径长度为3,依赖2的长度为2,最终间接依赖 D(2.0)将从 A->X->D(2.0) 路径引入到 A 中。

3.2 先声明者优先

在引入路径长度相同的前提下,POM 文件中依赖声明的顺序决定了间接依赖会不会被解析使用,顺序靠前的优先使用。

例如,A 存在以下依赖关系:
A->B->D(1.0)
A->X->D(2.0)

D 是 A 的间接依赖,其两条引入路径的长度都是 2,此时 Maven 依赖调节的第一原则已经无法解决,需要使用第二原则:先声明者优先。如果 B 的依赖先在依赖中声明,则D(1.0)会被最终引入到 A 中,在POM中的代码如下:

<dependencies>
    ...
    <dependency>
        ...
        <artifactId>B</artifactId>
        ...
    </dependency>
    ...
    <dependency>
        ...
        <artifactId>X</artifactId>
        ...
    </dependency>
    ...
</dependencies>

四、依赖管理的关键标签

4.1 parent

  parent标签指定当前项目以另一个项目为父项目,一般场景是多个项目需要指定同一个副项目,如果只是一对一的依赖,直接使用dependency就可以了。

  parent类似与基类,它定义了一个Maven项目的基本信息,包括groupId、artifactId、version等。当一个项目需要继承另一个项目的基本信息时,可以在子项目的pom.xml文件中使用parent元素来引用父项目的POM文件。这样,子项目就可以继承父项目的基本信息,包括依赖管理、插件管理等。

  创建一个parent项目,打包类型为pom(parent项目只能是pom,不包含任何代码),parent项目中不存放任何代码,只是管理多个项目之间公共的依赖。

  super-pom.xml是Maven中所有pom.xml文件的默认父pom.xml文件

4.2 dependencyManagement

  dependencyManagement是一个机制,它可以让多个模块共享同一个依赖版本号,从而避免版本冲突和重复依赖的问题。

  具体来说,当一个项目中有多个模块时,每个模块都可以声明自己的依赖,但是如果每个模块都声明了不同版本的同一个依赖,就会导致版本冲突和重复依赖的问题。为了解决这个问题,可以在父模块的pom.xml文件中使用dependencyManagement元素来声明依赖的版本号,然后在子模块中引用这个版本号即可。

  使用dependencyManagement的好处是,可以让项目中的所有模块都使用相同的依赖版本号,从而避免版本冲突和重复依赖的问题。此外,还可以方便地升级依赖版本号,只需要修改父模块的pom.xml文件即可,而不需要修改每个子模块的pom.xml文件。

  总的来说,parent和dependencyManagement都是用于管理依赖的机制,但它们的作用不同。parent用于定义项目的基本信息,dependencyManagement用于管理依赖版本号,一般会有专门的parent POM进行dependencyManagement的相关配置。在实际开发中,可以根据需要使用这两个机制来管理依赖。

4.3 排除依赖 exclusions

排除依赖是使用 exclusions 元素实现的,该元素下可以包含若干个 exclusion 子元素,用于排除若干个间接依赖

  • 排除依赖是控制当前项目是否使用其直接依赖传递下来的间接依赖;
  • exclusions 元素下可以包含若干个 exclusion 子元素,用于排除若干个间接依赖;
  • exclusion 元素用来设置具体排除的间接依赖,该元素包含两个子元素:groupId 和 artifactId,用来确定需要排除的间接依赖的坐标信息;
  • exclusion 元素中只需要设置 groupId 和 artifactId 就可以确定需要排除的依赖,无需指定版本 version

4.4 可选依赖 optional

依赖声明中使用 optional 元素,将其设置成可选依赖,示例配置如下:

    <dependencies>
        <dependency>
            <groupId>com.mytest.common</groupId>
            <artifactId>test-zxy</artifactId>
            <version>1.0-SNAPSHOT</version>
            <!--设置可选依赖  -->
            <optional>true</optional>
        </dependency>
    </dependencies>

关于 optional 元素及可选依赖说明如下:

  • 可选依赖用来控制当前依赖是否向下传递成为间接依赖;
  • optional 默认值为 false,表示可以向下传递称为间接依赖;
  • optional 取值为 true,则表示当前依赖不能向下传递成为间接依赖。
posted @ 2023-07-25 20:42  staticFinal  阅读(725)  评论(0)    收藏  举报