如何解决多模块项目中模块之间的依赖关系?

时间:2013-02-04 19:35:35

标签: maven dependency-management multi-module

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

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

我理解为什么Maven抱怨 - moduleA还没有构建,因此当执行脱机目标时,我的本地或内部存储库中没有moduleA:jar工件。但IMHO插件应该以不同方式处理这些模块间依赖关系。在这种情况下,它应该简单地忽略它。有人可能认为我可以简单地执行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无法解析模块间依赖性。在这种情况下,这是由antrun插件中的@requiresDependencyResolution引起的。

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

6 个答案:

答案 0 :(得分:27)

Maven具有“reactor”的概念,其中在单次运行中构建的工件(例如maven package)可用于构建期间的依赖性解析。例如,如果您的依赖图生成构建顺序moduleA moduleB moduleC,并且您执行mvn package,Maven将构建moduleA,打包其工件并将其添加到reactor,然后构建moduleB,将其打包并将其添加到reactor,然后是moduleC。这意味着moduleB可以访问moduleA的工件以进行依赖性解析,而moduleC可以访问moduleA和moduleB。这仅在实际构建工件时才有效,即当您运行包目标时。

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

简而言之,问题的解决方案是mvn package dependency:go-offline。这不会在本地存储库中安装工件(我认为这是非常糟糕的做法),但在构建期间将它们放入反应堆中,这意味着Maven将能够解决来自你的moduleB到已经构建的moduleA。不利的一面是每个模块都将进行测试和打包,如果你想做的只是做dependency:go-offline,这是很多工作。

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

答案 1 :(得分:2)

这是finally been resolvedMaven 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>

答案 2 :(得分:1)

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

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

一旦构建完成,你就可以继续用B做同样的事情,然后逐步做C.然后一步一步。

这里要记住的一点是,它有时可以使用本地仓库中的旧A快照构建B.如果存在签名更改或B所需的新内容,则只需要在repo中使用A build的新快照。

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

最后并不是说,当人们的构建时间太长时,通常会出现这类问题。有几种方法可以使构建更快:

  1. 获得更快的硬件。构建计算机,磁盘存储或网络速度是升级成本低于浪费慢速构建时间的典型组件。
  2. 不构建不需要重建的东西,使构建更快。 (例如,我有一个构建,每次重建所有生成的代码。我在构建中添加了一些东西,使它不会这样做,除非生成的代码的依赖性发生了变化。)
  3. 加快测试速度。有时这意味着将测试分成两部分。第1部分是快速测试,第2部分是慢速测试。在任何代码检查或工件发布之前,对每个构建和慢速测试运行快速测试。
  4. 将多模块构建分解为2个或更多单独的构建,并使用人工智能来决定何时重建事物。当一些罐子稳定并且不再有太大变化时,这种效果很好。
  5. 填写您自己的方法,使构建更快。

答案 3 :(得分:1)

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

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

请投票支持。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

从Maven依赖插件v3.1.2开始, dependency:go-offline 目标将支持该目标。相关的jira票据MDEP-204和修补程序23b7ca8790ae14175ed8e3a20c75c6274efe5ad8已修复。