多模块项目构建期间模块之间的 Maven 依赖关系解析
Maven dependency resolution between modules during a multi-module project build
我遇到了一些以前没有预料到的 Maven 行为。
例如我们有一个多模块项目 A:
A
|
--- api
--- impl
impl 模块使用 api 作为依赖项:
<dependency>
<groupId>examle</groupId>
<artifactId>api</artifactId>
</dependency>
当我 运行 mvn clean test
整个应用程序 Maven 成功完成时。
当我为 impl 模块执行相同的命令时,它们 maven 失败,异常如下:
[ERROR] Failed to execute goal on project impl: Could not resolve
dependencies for project A:impl:jar:1.0-SNAPSHOT: Could not find artifact
A:api:jar:1.0-SNAPSHOT in maven-public
所以我的问题是 maven 如何解决未构建到 jar 文件中并推送到 local/remote 存储库中的依赖项。在所有教程中,据说 maven 在本地存储库中查找依赖项,如果找不到,则会在远程存储库中搜索,并且它对 SNAPSHOTS 的行为略有不同。
但在我的情况下,我 运行 测试阶段并且即使在目标 repo 中也不构建 jar 文件
为了清楚起见,您在多模块项目中使用此命令 运行 注意到了此行为:
mvn clean test
但是您会有相同的行为,即:在您 运行 的任何阶段,例如:
mvn test
mvn compile
mvn package
事实上关于这一点的 Maven 文档并不明确。
您可以阅读 the Guide to Working with Multiple Modules :
The Reactor
The mechanism in Maven that handles multi-module projects is referred
to as the reactor. This part of the Maven core does the following:
Collects all the available modules to build
Sorts the projects into the correct build order
Builds the selected projects in order
您可以猜测,如果模块的顺序对 Maven 构建很重要,则可能意味着模块的构建依赖于先前构建的依赖模块的构建。这解释了如果您在 <modules>
中指定的顺序在依赖项方面不正确(正确的顺序是必须在用户依赖项之前声明使用的依赖项),则由反应器完成排序。
当然有一些用例需要将 Maven 工件安装到本地存储库中,例如(不详尽):
- 您没有使用多模块项目
- 整个多模块项目的构建时间很长。您希望通过构建一些特定的工件来节省时间,而不是构建多模块项目。
- 多模块项目中包含的一个或多个模块被其他项目shared/used。
通过使用 -X
标志(调试标志)执行 maven 构建命令,您将看到 Maven 为每个模块构建计算模块之间的依赖关系。
例如,对于您的示例,您应该看到 impl
build :
DEBUG] === PROJECT BUILD PLAN
================================================
[DEBUG] Project: A:impl:0.0.1-SNAPSHOT
[DEBUG] Dependencies (collect): []
[DEBUG] Dependencies (resolve): [compile, test]
稍后检测模块间依赖性:
[DEBUG] A:impl:jar:0.0.1-SNAPSHOT
[DEBUG] A:api:jar:0.0.1-SNAPSHOT:compile
这里有更详细的摘录:
[DEBUG] =======================================================================
[DEBUG] Dependency collection stats: {ConflictMarker.analyzeTime=23166, ConflictMarker.markTime=13490, ConflictMarker.nodeCount=2, ConflictIdSorter.graphTime=31377, ConflictIdSorter.topsortTime=6158, ConflictIdSorter.conflictIdCount=1, ConflictIdSorter.conflictIdCycleCount=0, ConflictResolver.totalTime=51611, ConflictResolver.conflictItemCount=1, DefaultDependencyCollector.collectTime=368903, DefaultDependencyCollector.transformTime=134014}
[DEBUG] A:impl:jar:0.0.1-SNAPSHOT
[DEBUG] A:api:jar:0.0.1-SNAPSHOT:compile
因此,在构建 impl
期间执行的插件也将有一个包含 api
模块的已编译 类 的类路径。
例如,编译器插件执行的调试跟踪显示:
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ impl ---
...
[DEBUG] (f) classpathElements = [C:\...\test-parent-pom\impl\target\classes, C:\...\test-parent-pom\api\target\classes]
我遇到了一些以前没有预料到的 Maven 行为。 例如我们有一个多模块项目 A:
A
|
--- api
--- impl
impl 模块使用 api 作为依赖项:
<dependency>
<groupId>examle</groupId>
<artifactId>api</artifactId>
</dependency>
当我 运行 mvn clean test
整个应用程序 Maven 成功完成时。
当我为 impl 模块执行相同的命令时,它们 maven 失败,异常如下:
[ERROR] Failed to execute goal on project impl: Could not resolve
dependencies for project A:impl:jar:1.0-SNAPSHOT: Could not find artifact
A:api:jar:1.0-SNAPSHOT in maven-public
所以我的问题是 maven 如何解决未构建到 jar 文件中并推送到 local/remote 存储库中的依赖项。在所有教程中,据说 maven 在本地存储库中查找依赖项,如果找不到,则会在远程存储库中搜索,并且它对 SNAPSHOTS 的行为略有不同。
但在我的情况下,我 运行 测试阶段并且即使在目标 repo 中也不构建 jar 文件
为了清楚起见,您在多模块项目中使用此命令 运行 注意到了此行为:
mvn clean test
但是您会有相同的行为,即:在您 运行 的任何阶段,例如:
mvn test
mvn compile
mvn package
事实上关于这一点的 Maven 文档并不明确。
您可以阅读 the Guide to Working with Multiple Modules :
The Reactor
The mechanism in Maven that handles multi-module projects is referred to as the reactor. This part of the Maven core does the following:
Collects all the available modules to build
Sorts the projects into the correct build order
Builds the selected projects in order
您可以猜测,如果模块的顺序对 Maven 构建很重要,则可能意味着模块的构建依赖于先前构建的依赖模块的构建。这解释了如果您在 <modules>
中指定的顺序在依赖项方面不正确(正确的顺序是必须在用户依赖项之前声明使用的依赖项),则由反应器完成排序。
当然有一些用例需要将 Maven 工件安装到本地存储库中,例如(不详尽):
- 您没有使用多模块项目
- 整个多模块项目的构建时间很长。您希望通过构建一些特定的工件来节省时间,而不是构建多模块项目。
- 多模块项目中包含的一个或多个模块被其他项目shared/used。
通过使用 -X
标志(调试标志)执行 maven 构建命令,您将看到 Maven 为每个模块构建计算模块之间的依赖关系。
例如,对于您的示例,您应该看到 impl
build :
DEBUG] === PROJECT BUILD PLAN ================================================ [DEBUG] Project: A:impl:0.0.1-SNAPSHOT [DEBUG] Dependencies (collect): [] [DEBUG] Dependencies (resolve): [compile, test]
稍后检测模块间依赖性:
[DEBUG] A:impl:jar:0.0.1-SNAPSHOT [DEBUG] A:api:jar:0.0.1-SNAPSHOT:compile
这里有更详细的摘录:
[DEBUG] ======================================================================= [DEBUG] Dependency collection stats: {ConflictMarker.analyzeTime=23166, ConflictMarker.markTime=13490, ConflictMarker.nodeCount=2, ConflictIdSorter.graphTime=31377, ConflictIdSorter.topsortTime=6158, ConflictIdSorter.conflictIdCount=1, ConflictIdSorter.conflictIdCycleCount=0, ConflictResolver.totalTime=51611, ConflictResolver.conflictItemCount=1, DefaultDependencyCollector.collectTime=368903, DefaultDependencyCollector.transformTime=134014} [DEBUG] A:impl:jar:0.0.1-SNAPSHOT [DEBUG] A:api:jar:0.0.1-SNAPSHOT:compile
因此,在构建 impl
期间执行的插件也将有一个包含 api
模块的已编译 类 的类路径。
例如,编译器插件执行的调试跟踪显示:
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ impl --- ... [DEBUG] (f) classpathElements = [C:\...\test-parent-pom\impl\target\classes, C:\...\test-parent-pom\api\target\classes]