在一个多模块的maven项目中,我可以制作一个模块来根据另一个模块的DependencyReducedPom计算传递依赖吗?

Posted

技术标签:

【中文标题】在一个多模块的maven项目中,我可以制作一个模块来根据另一个模块的DependencyReducedPom计算传递依赖吗?【英文标题】:In a multi-module maven project, can I make a module to calculate transitive dependencies based on the DependencyReducedPom of another module? 【发布时间】:2020-12-25 07:51:52 【问题描述】:

这似乎是一个简单的问题,但由于 maven 极其严格的生命周期和阶段范式,我发现它很困难:

假设在一个多模块的maven项目中,在不同阶段使用了几个插件来将pom.xml重写为更有效的版本,值得注意的例子是:

maven-shade-plugin(如果启用了<createDependencyReducedPom>):当需要发布着色的 uber-jar 时,该插件可以摆脱不需要包含的依赖项。始终在打包阶段执行。

flatten-maven-plugin:允许模块发布的 pom.xml 不再依赖于父级的 pom,通过将属性引用替换为它们的实际值。可以在任何阶段执行,但为了保持与 maven-shade-plugin 的互操作性,它也仅限于打包阶段(参见https://issues.apache.org/jira/browse/MSHADE-323)

当它们与其他模块组合时,maven reactor 构建引擎似乎经常摸索要使用哪个版本的重写 pom 来计算传递依赖。理想情况下,应该使用打包阶段之后的最终版本。但在最新的 maven 版本 (3.6.3) 中,它只能在重写之前使用 pom.xml,不会减少依赖关系并且所有属性都没有正确替换。

我的问题是:

    这个设计的意义何在?为什么在所有插件都明确替换它时使用半生不熟的 pom.xml?

    如何覆盖此行为,以便始终生成和使用最终版本的 pom.xml,而不管请求的 maven 目标如何?

更新 1:目前我正在使用一个简单的规避方法:

将第一个模块拆分为一个独立的 maven 项目,在打包阶段调用 maven-shade 和 flatten-maven 插件。 (我没有直接的证据,但我怀疑这就是像 spark-project.hive https://mvnrepository.com/artifact/org.spark-project.hive/hive-common 这样重新打包的依赖项的制作方式,相关讨论请参见 https://issues.apache.org/jira/browse/SPARK-20202)

使用shell脚本依次编译/发布上述项目和主多模块项目。

我不是 shell 脚本的忠实拥护者,我认为这背叛了 JVM 社区所珍视的与平台无关的壮举。所以如果你有更好的解决方案,请在这里发帖,我会根据人气接受。

非常感谢您的意见

【问题讨论】:

那么您遇到的具体问题是什么?如果 Maven 读取的是构建 POM,而不是最终部署的 POM,为什么会给您带来问题? 后果是: 1. IDE 在执行测试和分析时会附加无用的 jars。 2.下游模块中其他依赖传递依赖作为证据的插件会出现奇怪的行为。由于 JVM 的类加载算法,这些问题很可能在运行时处于休眠状态,但不能保证 抱歉,我仍然不明白为什么您需要规避并且不能只是构建。你能举一个具体的例子说明哪里出了问题吗? 我想如果你能添加一个具体的例子,这将对这个问题有很大帮助。 【参考方案1】:

第一件事是:maven's extremely rigorous paradigm of lifecycles and phases: 那些生命周期和阶段有很好的理由。

此外,您提到几个插件会重写 pom.xml 文件。唯一的例子是你提到的maven-shade-plugin和flatten-maven-plugin。

除此之外,正如您提到的 maven-shade-plugin 意图:

这个插件提供了将工件打包到 uber-jar 中的能力,包括它的依赖项和遮蔽 - 即重命名 - 一些依赖项的包。

目的是隐藏依赖关系(解压 jars 并重新打包到一个 jar 中)并制作一个可执行的 jar(这也可以通过 maven-assembly-plugin 完成)...而不是摆脱依赖关系。

flatten-maven-plugin 的想法是删除 pom 文件中不需要的部分供以后使用(Build POM vs. Consumer POM)。目前这部分将与 Maven 3.7.0 一起成为 Maven Core 的一部分...这是将build pom 和消费者 pom 分开的重要的第一步。

所以让我们来看看 reactor 构建引擎,它旨在根据依赖关系定义构建顺序。

理想情况下,应该使用打包阶段之后的最终版本

这意味着在打包之前和打包之后的阶段之间(对于此类插件的每次执行)具有不同的顺序和不同的依赖关系(包括传递依赖关系)。这将导致不可重复的结果。除了重新计算整个依赖树等的事情。

但在最新的 maven 版本 (3.6.3) 中,它只能在重写之前使用 pom.xml,不会减少依赖关系并且所有属性都没有正确替换。

所有以前的版本也是如此。此外, pom.xml 在构建的最开始时被读取...

这个设计的意义何在?为什么在所有插件都明确替换它时使用半生不熟的 pom.xml?

您究竟想知道什么?还提到了只有两个具有不同意图的插件(并非所有插件)。

如何覆盖此行为,以便始终生成和使用最终版本的 pom.xml,而不管请求的 maven 目标如何?

没有选项可以覆盖此行为,因为它不存在。这意味着要重写大部分 Maven 核心。

【讨论】:

“...不要摆脱依赖”,不再是,<createDependencyReducedPom> 是官方功能,默认启用 仅供参考maven.apache.org/plugins/maven-shade-plugin/…。考虑到这些信息,您几乎建议 maven 是一座沙堡,应该被抛弃 我知道这个选项存在,目的是删除在生成的 jar 中阴影的依赖项,而不是未使用的依赖项。否则将使用正在使用的项目的 pom,这在使用 maven-shade-plugin 的情况下是错误的。此外Considering this information, you almost suggested that maven is a sand castle and should be abandoned 嗯...我不知道你想用这个表达什么?我在哪里建议/得出结论?而且我看不到与被遗弃的 Maven 的关系? 对不起,我玩世不恭,我不会放弃 maven。然而,为了减轻这种范式的后果(请参阅我对问题的评论),现在我必须将一个整体项目分成 2 个,并使用胶水语言将它们粘在一起,以获得正确的 pom 版本。我应该每次都因为这些微不足道的原因而这样做吗?如果胶水语言到处泛滥,构建管道会退化成另一个蚂蚁吗?这些是我未来 10 年要问的问题

以上是关于在一个多模块的maven项目中,我可以制作一个模块来根据另一个模块的DependencyReducedPom计算传递依赖吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何配置SonarQube以显示多模块maven项目的所有模块?

如何在我的 Maven Spring Boot 多模块项目的测试中引用兄弟模块?

Maven多模块的开发项目搭建

Maven多模块项目循环依赖问题

多模块项目中的 Maven 测试依赖项

如何将maven多模块spring boot部署到docker容器