21

在使用 Maven 一段时间后,我对 Maven 为构建架构带来的许多特性感到兴奋,尤其是依赖关系管理。但是,我一次又一次地遇到一个问题——Maven 如何解决多模块项目之间的依赖关系。我想知道这是否是当前 Maven 实现的大缺陷和/或是否有任何令人满意的解决方法。

假设我有一个多模块 Maven 项目。Parent pom 包含三个模块——moduleA (jar)、moduleB (jar) 和moduleC(war)。B 依赖于 A,C 依赖于 B。够简单吗?现在我想mvn dependency:go-offline在父项目上运行,它应该解决所有依赖项并将它们带入本地 .m2 目录。它失败是因为 Maven 抱怨它在作用于模块 B 时无法解决模块 A 的依赖关系。因为所有这些模块都属于一个groupId,所以我什至尝试使用-DexcludeGroupIds=x.y.z排除这些模块依赖关系,但它仍然在同一点失败。

我理解为什么 Maven 抱怨 - moduleA 尚未构建,因此当执行脱机目标时,我的本地或内部存储库中没有 moduleA:jar 工件。但恕我直言,插件应该以不同的方式处理这些模块间依赖关系。在这种情况下,它应该简单地忽略它。有人可能会争辩说我可以简单地做mvn clean install,这会将 moduleA:jar 安装到本地存储库中。在那之后,跑步mvn dependency:go-offline肯定会起作用。但是这种解决方法违背了这个离线目标的目的。这个插件允许我们在不构建整个项目的情况下解析和拉取依赖项到我们的本地存储库中。我dependency:copy-dependencies在另一种情况下使用了目标,它也有同样的问题。

我在其他情况下也遇到了类似的问题:“mvn clean generate-source” could not resolve dependencies。当我运行时mvn clean compile,一切正常,但是当我运行时mvn clean generate-source,它失败了,因为 Maven 无法解决模块间依赖关系。在那种情况下,这是由@requiresDependencyResolutionantrun 插件引起的。

由于 antrun 插件和依赖插件都在 Maven 世界中非常流行,我相信我不是唯一遇到这个问题的人。有人找到任何解决方案/解决方法吗?

4

6 回答 6

31

Maven 有一个“反应器”的概念,其中在一次运行中构建的工件(例如maven package)可用于构建期间的依赖关系解析。例如,如果您的依赖关系图生成构建顺序 moduleA moduleB moduleC,而您这样做了mvn package,Maven 将构建 moduleA,打包其工件并将其添加到反应器中,然后构建模块B,将其打包并将其添加到反应器中,那么同样对于模块C。这意味着 moduleB 可以访问 moduleA 的工件以解决依赖关系,而 moduleC 可以访问 moduleA 和 moduleB。这仅在实际构建工件时才有效,即当您运行包目标时。

问题是,当您因为对工件(如您的dependency:go-offline示例)不感兴趣而不运行包目标时,已处理的模块的工件不会被构建,因此不会添加到反应器中。我也觉得这很烦人;我认为 Maven 应该查看其要构建的模块列表中的 POM 文件并在那里查看;但事实并非如此。

简而言之,解决您的问题的方法是mvn package dependency:go-offline. 这不会在您的本地存储库中安装工件(我认为这是非常糟糕的做法),但它在构建期间将它们放入反应器中,这意味着 Maven 将能够解决从您的模块 B 到模块 A 的依赖关系已经建成。缺点是每个模块都将被测试和打包,当你只想做的时候,这是很多工作dependency:go-offline

无论哪种方式,希望这会有所帮助。

于 2013-08-29T15:00:04.720 回答
3

Maven Dependency Plugin版本 3.1.2终于解决了这个问题。

您可以通过将版本固定在您的pom.xml

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.1.2</version>
            </plugin>
       </plugins>
    </pluginManagement>
</build>
于 2020-05-04T20:00:24.790 回答
2

我在这里创建了一个带有示例项目的 JIRA 票证:

https://issues.apache.org/jira/browse/MDEP-516

请为它投票。

于 2016-01-16T13:18:44.030 回答
1

您解释了为什么它不起作用,以便您了解问题。你的问题是当它找不到 A.jar 时它会停止,但只有在你开始构建 B 时才会发生这种情况。所以有一种有时有用的策略。

你必须自己弄乱A。只需构建 A。使用加载依赖项的计划,然后构建它。

构建完成后,您可以继续使用 B 和 C 执行相同的操作。逐步进行。

这里要记住的一件事是,有时可以在本地存储库中使用 A 的旧快照构建 B。如果 B 需要签名更改或新内容,您只需要在 repo 中构建 A 的新快照。

这里也有一些讨论:Maven Modules + Building a Single Specific Module

当人们的构建时间过长时,通常不会出现最后一个问题。有几种方法可以加快构建速度:

  1. 获得更快的硬件。构建计算机、磁盘存储或网络速度是典型的组件,升级成本比浪费慢构建所花费的时间要便宜。
  2. 通过不构建不需要重建的东西来加快构建速度。(例如,我有一个构建,每次都重新构建所有生成的代码。我在构建中添加了一些东西,除非生成代码的依赖关系发生变化,否则它不会这样做。)
  3. 加快测试速度。有时这意味着将测试分成两部分。第 1 部分是快速测试,第 2 部分是慢速测试。在任何代码签入或发布工件之前,对每个构建运行快速测试和慢速测试。
  4. 将多模块构建分解为 2 个或多个单独的构建,并使用人类智能来决定何时重建事物。当一些罐子稳定并且不再有太大变化时,这很有效。
  5. 填写您自己的方法以使构建更快。
于 2013-02-04T20:34:56.250 回答
0

我怀疑 Maven 是否可以实现这样的功能。虽然您的项目共享一个共同的父项并相互依赖,但 Maven 不可能知道在哪里可以找到这些项目以构建它们。它也无法确定是否只需要构建项目,或者您是否为依赖项指定了错误的版本号。

于 2013-02-04T20:35:11.710 回答
0

从 Maven Dependency Plugin v3.1.2 开始, dependency:go-offline目标将支持这一点。相关的 jira 票证MDEP-204和补丁23b7ca8790ae14175ed8e3a20c75c6274efe5ad8与修复。

于 2020-02-23T11:39:45.233 回答