多模块项目构建期间模块之间的 Maven 依赖关系解析

Posted

技术标签:

【中文标题】多模块项目构建期间模块之间的 Maven 依赖关系解析【英文标题】:Maven dependency resolution between modules during a multi-module project build 【发布时间】:2018-12-28 12:30:58 【问题描述】:

我遇到了一些以前没有预料到的 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 的行为略有不同。

但在我的情况下,我运行测试阶段并且即使在目标 repo 中也不构建 jar 文件

【问题讨论】:

【参考方案1】:

为了清楚起见,您注意到从多模块项目运行此命令时的这种行为:

mvn clean test

但是您将有相同的行为,即:在模块之间解决依赖关系并使其可用,而无需事先将它们安装在本地存储库中,并运行任何阶段,例如:

mvn test
mvn compile
mvn package

事实上,关于这一点的 Maven 文档并不明确。

您可以在the Guide to Working with Multiple Modules阅读:

反应堆

Maven中处理多模块项目的机制被引用 作为反应堆。这部分 Maven 核心执行以下操作:

收集所有可用模块进行构建

将项目排序为正确的构建顺序

按顺序构建选定的项目

你可以猜到,如果模块的顺序对 Maven 构建很重要,这可能意味着模块的构建依赖于先前构建的依赖模块的构建。这解释了如果您在 &lt;modules&gt; 中指定的顺序在依赖项方面不正确(正确的顺序是必须在用户依赖项之前声明使用的依赖项),则反应器完成的排序。

当然,在某些用例中,您希望将 maven 工件安装到本地存储库中,例如(并非详尽无遗):

您没有使用多模块项目 整个多模块项目的构建很长。您只需要构建一些特定的工件来获得空闲时间,因此无需构建多模块项目。 多模块项目中包含的一个或多个模块被其他项目共享/使用。

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

调试] === 项目构建计划 ================================================= [调试] 项目:A:impl:0.0.1-SNAPSHOT [DEBUG] 依赖项(收集):[] [DEBUG] 依赖(解决):[编译,测试]

稍后检测模块间依赖关系:

[调试] A:impl:jar:0.0.1-SNAPSHOT [调试] A:api:jar:0.0.1-SNAPSHOT:compile

以下是更详细的摘录:

[调试] ================================================= ========================= [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 [调试] A:impl:jar:0.0.1-SNAPSHOT [调试] A:api:jar:0.0.1-SNAPSHOT:compile

因此,在构建 impl 期间执行的插件也将具有包含 api 模块的已编译类的类路径。 例如编译器插件执行的调试痕迹显示:

[信息] --- maven-compiler-plugin:3.1:compile (default-compile) @ impl --- ... [调试] (f) 类路径元素 = [C:\...\test-parent-pom\impl\target\classes, C:\...\test-parent-pom\api\target\classes]

【讨论】:

在我的例子中:'mvn compile',然后是'mvn install',来自父项目。如果您正在使用 SpringBoot 或某些项目构建 'fat' 或 'uber' jars(例如,下一个附带的 'spring-boot-maven-plugin':'maven-shade-plugin' 或类似的),请注意不要使用额外的'maven-install-plugin' 用于在本地 maven 存储库中复制模块依赖项,在项目编译期间会发生依赖项解析。

以上是关于多模块项目构建期间模块之间的 Maven 依赖关系解析的主要内容,如果未能解决你的问题,请参考以下文章

使用maven搭建多模块项目

笔记:Maven 反应堆

Maven管理多模块应用

如何正确地实现Java模块与inter-module Maven构建测试依赖关系

使用maven模块开发

maven一个web模块能依赖另一个web模块吗