在 Maven 4 中使用多个模块的指南

(如果您正在使用 Maven 3,请参阅本指南的 Maven 3 版本

正如在 POM 的介绍中看到的,Maven 除了项目继承之外还支持项目聚合。本节概述了 Maven 如何处理具有多个模块的项目,以及如何更有效地使用它们。

反应堆

Maven 中处理多模块项目的机制称为reactor。Maven 核心的这一部分执行以下操作:

  • 收集所有可用的模块来构建
  • 将模块排序为正确的构建顺序
  • 选择要构建的模块
  • 按顺序构建选定的模块

收集模块

模块集合从一个聚合器项目开始。<modules>该项目使用元素定义了它所包含的模块。这是一个递归过程,因此聚合器可以拥有本身就是聚合器的子模块。

要使此过程起作用,您从哪个 POM 开始都没有关系。Maven 试图通过在目录结构中向上遍历直到找到具有.mvn同级目录的 POM 来查找多模块项目的根目录。这允许 Maven 解决对来自同一个多模块项目的模块的依赖关系,而不管起始 POM 的位置。当 Maven 找不到根时,它假定起始 POM 是根。.mvn为了获得一致的行为,请在项目的根目录中创建一个目录。

有两种方法可以指向起始 POM。默认情况下,Maven 读取pom.xml工作目录中的文件。使用-f,您可以指向另一个 POM。

排序模块

因为多模块构建中的模块可以相互依赖,所以反应器以确保在需要之前构建任何项目的方式对所有项目进行排序是很重要的。

排序项目时遵循以下关系:

  • 项目依赖于构建中的另一个模块
  • 插件声明,其中插件是构建中的另一个模块
  • 插件依赖于构建中的另一个模块
  • 构建中另一个模块的构建扩展声明
  • 元素中声明的顺序<modules>(如果没有其他规则适用)

请注意,仅使用“实例化”引用 -dependencyManagement元素pluginManagement不会导致反应器排序顺序发生变化。

选择模块

默认情况下,Maven 构建它收集的所有模块。但是,您可以选择这些模块的一个子集来使用命令行标志进行构建。这些标志分为三类:

  • 包容与排斥
  • 模块之间的关系
  • 处理失败

本节以这些标志如何相互关联结束。

包容与排斥

使用--projects您可以指定要构建的模块。您可以通过指定以逗号分隔的项目选择器列表来执行此操作。项目选择器是一个字符串,由groupId:artifactId、only:artifactId或模块的相对路径组成。

可以选择一个模块(默认),或从构建中排除。!您可以通过在选择器前面加上or来排除模块-。要显式选择模块,请在其前面加上+.

When a selector does not resolve to an existing module, Maven fails the build. ?您可以通过添加前缀来防止这种情况。此前缀应始终位于其他前缀之后。

模块之间的关系

项目中的模块可以有两种类型的关系:父/子和依赖/依赖。

选择父模块(聚合器)时,Maven 也会自动选择子模块。同样,Maven 排除了被排除的父(聚合器)的子模块。要防止这种递归行为,请--projects结合--non-recursive.

Maven 知道多模块项目中模块之间的依赖关系。使用--also-make,Maven 在构建中包含所选项目的所有依赖项。同样,--also-make-dependents让 Maven 包含依赖于所选项目的所有模块。

处理失败

有几种方法可以自定义反应器如何处理故障。 --fail-at-end在构建尽可能多的模块后构建失败。在这种情况下,仍然会构建不依赖于失败模块的模块。 --fail-fast相比之下,一旦一个模块失败,构建就会失败。这是默认行为。 --fail-never忽略构建失败。

当构建失败并且您想重新启动它时,您可以跳过构建之前使用--resume. 要从特定模块恢复构建,您可以使用--resume-from <selector>.

把它放在一起

如前所述,Maven 包括反应器中的所有模块,即使起始 POM 不是项目的根目录。然后反应器使用以下步骤选择要构建的模块:

  1. 将完整的模块列表缩减为起始 POM 及其子模块的模块。
  2. 进一步将此列表减少到包含的所有模块--projects,如果--resume已给出,则为先前失败的构建的剩余模块。
  3. 通过删除在 选择的模块之前构建的所有模块,进一步减少此列表--resume-from
  4. 最后,通过删除所有被排除在外的模块--projects(使用!or-前缀)来进一步减少这个列表。

步骤 1、2 和 3 中的每一个都尊重--also-make--also-make-dependents标志,如果它们被给出的话。

命令行选项

无需特殊配置即可利用反应器,但可以自定义其行为。

可以使用以下命令行开关:

短的 概括 细节
--file -f 选择包含 POM 文件的替代 POM 文件或目录。 收集模块
--non-recursive -N 忽略起始 POM 中可能存在的任何子模块。与 结合使用时-pl,忽略选定模块的子模块。 收集模块模块之间的关系
--projects -pl 指定要从构建中包含或排除的模块。 包容与排斥
--also-make -am 构建指定的模块,以及它们在反应器中的任何依赖项。 模块之间的关系
--also-make-dependents -amd 构建指定的模块,以及任何依赖它们的模块。 模块之间的关系
--resume-from -rf 从指定项目恢复反应器(例如,当它在中间失败时)。 处理失败
--resume -r 从先前构建失败的模块恢复反应器。 处理失败
--fail-fast -ff 每当模块构建失败时立即停止整体构建。这是默认行为。 处理失败
--fail-at-end -fae 如果特定模块构建失败,则继续反应器的其余部分,并在最后报告所有失败的模块。 处理失败
--fail-never -fn 无论项目结果如何,构建都不会失败。 处理失败

Maven 3 和 4 之间的差异

示例多模块项目

下表说明了在 Maven 3 和 4 之间发生变化的多个场景。它们假设项目结构如上所示。

设想 结果(按顺序) Maven 3 Maven 4
构建聚合器及其子级 模块-c,模块-c-1,模块-c-2 mvn compile -pl module-c, module-c-1, module-c-2 mvn compile -pl module-c
构建一个聚合器并忽略它的子节点 模块-c,模块-c-1,模块-c-2 mvn compile -pl module-c mvn compile -pl module-c -N
还要使依赖关系超出当前范围 父、模块-a、模块-b、模块-c、模块-c-2 不适用 cd module-c/module-c-2 && mvn compile -am
还要使受抚养人超出当前范围 模块-a、模块-b、模块-c-2 不适用 cd module-a && mvn compile -amd
从模块恢复并构建所有依赖项 父、模块-a、模块-b、模块-c、模块-c-2 不适用 mvn compile -rf :module-c-2 -am要么mvn compile -r -am
在具有项目依赖关系的一个子模块上运行特定目标 模块-c-2 mvn install && mvn jetty:run -f module-c/module-c-2 mvn compile && mvn jetty:run -f module-c/module-c-2

更多信息