在使用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世界中非常流行,我相信我并不是唯一遇到此问题的人。有人找到任何解决方案/解决方法吗?
答案 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 resolved的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>
答案 2 :(得分:1)
您解释了为什么它不起作用所以您了解问题。你遇到的问题是当它找不到A.jar时会停止,但这只会在你建立B时发生。所以有一种有时候很有用的策略。
你必须自己搞乱A。只需构建A.使用加载依赖项的计划,然后构建它。
一旦构建完成,你就可以继续用B做同样的事情,然后逐步做C.然后一步一步。
这里要记住的一点是,它有时可以使用本地仓库中的旧A快照构建B.如果存在签名更改或B所需的新内容,则只需要在repo中使用A build的新快照。
这里也有一些讨论:Maven Modules + Building a Single Specific Module
最后并不是说,当人们的构建时间太长时,通常会出现这类问题。有几种方法可以使构建更快:
答案 3 :(得分:1)
答案 4 :(得分:0)
我怀疑使用Maven可以实现这样的功能。虽然您的项目共享一个共同的父项并相互依赖,但Maven无法知道在哪里找到这些项目以构建它们。它也无法确定是否只需要构建项目,或者是否为依赖项指定了错误的版本号。
答案 5 :(得分:0)
从Maven依赖插件v3.1.2开始, dependency:go-offline 目标将支持该目标。相关的jira票据MDEP-204和修补程序23b7ca8790ae14175ed8e3a20c75c6274efe5ad8已修复。