多模块项目构建过程中的模块间Maven依赖解析

3

我面临着一些意料之外的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文件并推送到本地/远程存储库的依赖项。在所有教程中都说,Maven会在本地存储库中查找依赖项,如果找不到,则在远程存储库中搜索,并且对于SNAPSHOTS有一些不同的行为。
但是在我的情况下,我运行测试阶段,甚至没有在目标存储库中构建JAR文件。
1个回答

8
为了让事情更明确,您注意到了从多模块项目中运行此命令的行为:
mvn clean test

但是你会得到相同的行为,即:在运行任何阶段时都会解决依赖关系并在模块之间使用它们,而无需事先将它们安装在本地存储库中。
mvn test
mvn compile
mvn package

事实上,Maven文档对此点并不明确。您可以在多模块协作指南中阅读到以下内容:
引用: 反应堆 Maven中处理多模块项目的机制称为反应堆。 Maven核心的这一部分执行以下操作: 收集所有可用的要构建的模块 将项目按正确的构建顺序进行排序 按顺序构建所选项目
您可以猜测,如果模块的顺序对于Maven构建很重要,那么这可能意味着模块的构建依赖于先前构建的依赖模块的构建。 这就解释了反应堆所做的排序,如果中指定的顺序在依赖关系方面不正确(正确的顺序是必须在用户依赖关系之前声明使用的依赖关系),则会出现这种情况。
当然,有一些用例需要将Maven工件安装到本地存储库中,例如(非详尽):
  • 您没有使用多模块项目。
  • 整个多模块项目的构建时间很长。您想通过只构建某些特定构件来节省时间,而不构建多模块项目。
  • 多模块项目中包含一个或多个被其他项目共享/使用的模块。

通过在Maven构建命令中执行-X标志(调试标志),您将看到Maven计算每个模块构建之间的依赖关系。
例如,在您的示例中,您应该看到impl构建的依赖关系:

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] 依赖收集统计信息: {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]

在我的情况下:从父项目开始,先运行'mvn compile',然后再运行'mvn install'。如果您正在使用SpringBoot或某些构建“fat”或“uber” jar的项目(例如带有'spring-boot-maven-plugin'的下一个插件:'maven-shade-plugin'或类似插件),请注意不要使用额外的'maven-install-plugin'将模块依赖项复制到本地maven存储库中,在项目编译期间解析依赖项。 - Felix Aballi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接