20

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

我的问题是:

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

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

4

3 回答 3

17
  1. Maven 没有办法实现您的要求。即使您应该为直接依赖项设置特定版本,但由于看似无关的更改,您的传递依赖项很容易被无意更改。例如,添加对新库的依赖项可以为您提供现有传递依赖项的旧版本。

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

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

    我见过许多由于开发人员不小心更改传递依赖关系而导致的运行时问题。

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

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

于 2019-02-07T19:34:50.973 回答
4

依赖锁定是 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

于 2020-01-23T22:38:16.403 回答
-1

Maven、SBT 和 Gradle 都有您所描述的内容。它被称为“使用发布(或固定)版本”。与版本范围或快照 ( )1.2.3相比,发布的版本看起来像。[1.2.3,)1.2.3-SNAPSHOT

如果您的所有依赖项都使用已发布的版本,您将实现您所描述的。

版本范围也是版本的有效形式,具体取决于您的用例,但我通常建议不要使用它们,除非它们用于 parent POM-s,或者只是在积极开发期间。如果您确定相应的工件绝不会为您破坏任何东西(并且,相信我,这确实发生在版本范围内)。当您想保证代码将根据您最初设计和测试的内容构建和工作时,应使用固定版本。

pom.xml如果您严格定义依赖项的版本,则无需具有诸如“锁定文件”之类的功能或类似的功能。

如果您阅读有关依赖管理的文档,您会发现确实如此:

于 2017-06-13T15:10:57.413 回答