为什么 Gradle 或 Maven 没有依赖项版本锁定文件?



我最近在阅读NPM,Yarn,Paket,Cargo等包管理器时被引入了依赖版本锁定文件的概念。 我的理解是,它是一个列出所有直接和传递依赖项及其确切版本号的文件,因此后续构建可以保证使用一组等效的依赖项。 这似乎是一个理想的功能,因为许多包管理器已经或正在采用这个概念。

那么我的问题是:

  1. 为什么 Maven 或 Gradle 不使用锁定文件? 或者如果他们有,为什么我没有看到它?

  2. 在包管理器的依赖项解析策略中允许版本范围与仅允许精确版本有什么优缺点?

  1. Maven没有办法实现您的要求。即使为直接依赖项设置了特定版本(也应该这样做),传递依赖项也很容易由于看似不相关的更改而意外更改。例如,在新库上添加依赖项可以为您提供现有传递依赖项的旧版本。

    您需要的是一个dependencyManagement部分,列出所有直接和传递依赖项。您仍然无法检测是否删除或添加了传递依赖项,这是 NPM 提供的功能。缺少它的问题是您的所有依赖项都不再位于dependencyManagement部分中。要检测这些更改,您可以使用我编写的依赖项锁插件之类的东西。使用它也会降低将所有内容放在dependencyManagement部分中的重要性,因为将检测到传递依赖项中的更改。

    我还建议在您的构建中使用 https://maven.apache.org/enforcer/enforcer-rules/requireUpperBoundDeps.html,因为 Maven 选择在树中关闭的传递依赖项的版本,而不是如您所期望的那样的最高版本。

    我见过许多由开发人员意外更改传递依赖项引起的运行时问题。

    TL;DR:在Maven中,你确实需要类似锁定文件的东西,但由于历史意识形态的原因它不存在。

  2. 我不建议使用版本范围,因为它们会使您的构建不可重现。 当涉及到传递依赖关系时,它的行为也不像你想象的那样。

依赖关系锁定是 Gradle 5.0 中达到一定成熟度的一项功能: https://docs.gradle.org/current/userguide/dependency_locking.html

Gradle的实现灵感来自Nebula插件:https://github.com/nebula-plugins/gradle-dependency-lock-plugin

版本范围在用作锁定机制的任何更新的输入时确实运行良好。因此,对于 Gradle,您实际上可以只定位特定的依赖项,这些依赖项将解析您指定的版本范围:

gradle classes --update-locks org.apache.commons:commons-lang3,org.slf4j:slf4j-api

或者,你可以说"去更新我所有的部门":

gradle dependencies --write-locks

如果您正在研究自动化,指定解决策略也值得回顾:https://docs.gradle.org/current/userguide/dependency_resolution.html

最新更新