ChatGPT解决这个技术问题 Extra ChatGPT

如何告诉 Maven 使用最新版本的依赖项?

在 Maven 中,依赖项通常是这样设置的:

<dependency>
  <groupId>wonderful-inc</groupId>
  <artifactId>dream-library</artifactId>
  <version>1.2.3</version>
</dependency>

现在,如果您正在使用频繁发布的库,那么不断更新 标记可能会有些烦人。有什么方法可以告诉 Maven 始终使用最新的可用版本(来自存储库)?

@Martin我知道xyz-SNAPSHOT约定,但我正在考虑以最终版本发布到存储库的库(即从dream-library-1.2.3.jar 到dream-library-1.2.4.jar , 等等)。
为了构建可重复性,我真的不推荐这种做法(也不使用版本范围)。由于未知原因开始突然失败的构建比手动更新版本号更烦人。
@PascalThivent 如果您正在进行连续发布,那么手动更新 pom 中的发布号会很痛苦。我使用版本插件和 scm 插件来解决这个问题(见我的回答)。
@PascalThivent 两者都很烦人,但方式不同。我想根据我的情况在两者之间进行选择,而不是被迫使用一个,因为其他人认为这个会更好。
guava 库是最新版本的一个很好的例子,它从早期版本中删除了类,然后破坏了构建。 Maven 的心态是任何较新的版本都可以替换任何较早的版本,这在实践中并不成立。

n
nmatt

笔记:

6 年前提到的 LATESTRELEASE 元版本have been dropped for plugin dependencies in Maven 3 "for the sake of reproducible builds"。 (对于常规依赖项,它们仍然可以正常工作。)有关插件依赖项,请参阅此Maven 3 compliant solution

如果您总是想使用最新版本,Maven 有两个关键字可以用来替代版本范围。您应该小心使用这些选项,因为您不再控制正在使用的插件/依赖项。

当您依赖插件或依赖项时,您可以使用 LATEST 或 RELEASE 的版本值。 LATEST 是指特定工件的最新发布或快照版本,即特定存储库中最近部署的工件。 RELEASE 是指存储库中的最后一个非快照版本。通常,设计依赖于工件的非特定版本的软件并不是最佳实践。如果您正在开发软件,您可能希望使用 RELEASE 或 LATEST 作为一种方便,这样您就不必在第三方库的新版本发布时更新版本号。当您发布软件时,您应该始终确保您的项目依赖于特定版本,以减少您的构建或项目受到不受您控制的软件版本影响的机会。如果有的话,请谨慎使用 LATEST 和 RELEASE。

有关详细信息,请参阅 POM Syntax section of the Maven book。或在 Dependency Version Ranges 上查看此文档,其中:

方括号( [ & ] )表示“封闭”(包括)。

括号 ( ( & ) ) 表示“开放”(排他)。

这是一个说明各种选项的示例。在 Maven 存储库中,com.foo:my-foo 具有以下元数据:

<?xml version="1.0" encoding="UTF-8"?><metadata>
  <groupId>com.foo</groupId>
  <artifactId>my-foo</artifactId>
  <version>2.0.0</version>
  <versioning>
    <release>1.1.1</release>
    <versions>
      <version>1.0</version>
      <version>1.0.1</version>
      <version>1.1</version>
      <version>1.1.1</version>
      <version>2.0.0</version>
    </versions>
    <lastUpdated>20090722140000</lastUpdated>
  </versioning>
</metadata>

如果需要对该工件的依赖,您可以使用以下选项(当然可以指定其他 version ranges,此处仅显示相关选项):

声明一个确切的版本(将始终解析为 1.0.1):

<version>[1.0.1]</version>

声明一个显式版本(将始终解析为 1.0.1,除非发生冲突,此时 Maven 将选择匹配的版本):

<version>1.0.1</version>

声明所有 1.x 的版本范围(当前将解析为 1.1.1):

<version>[1.0.0,2.0.0)</version>

声明一个开放的版本范围(将解析为 2.0.0):

<version>[1.0.0,)</version>

将版本声明为 LATEST(将解析为 2.0.0)(从 maven 3.x 中删除)

<version>LATEST</version>

将版本声明为 RELEASE(将解析为 1.1.1)(从 maven 3.x 中删除):

<version>RELEASE</version>

请注意,默认情况下,您自己的部署将更新 Maven 元数据中的“最新”条目,但要更新“发布”条目,您需要从 Maven super POM 激活“发布配置文件”。您可以使用“-Prelease-profile”或“-DperformRelease=true”来执行此操作

值得强调的是,任何允许 Maven 选择依赖版本(LATEST、RELEASE 和版本范围)的方法都可能让您面临构建时间问题,因为更高版本可能有不同的行为(例如,依赖插件之前切换了默认值)值从真到假,结果令人困惑)。

因此,在发行版中定义确切的版本通常是一个好主意。正如 Tim's answer 所指出的,maven-versions-plugin 是用于更新依赖项版本的便捷工具,尤其是 versions:use-latest-versionsversions:use-latest-releases 目标。


我认为 LATEST/RELEASE 对于提供部署功能的插件非常重要。例如,我们使用插件将新版本的工件部署到我们的服务器。如果服务器发生变化,我们会发布新版本的插件,并且所有使用此插件的项目必须手动更新以使用新版本的部署插件。
@RichSeller 嘿里奇;在我发现这在 Maven 3.0 中不再可用之前,我花了一些时间来解决这个问题;)您是否考虑编辑答案,以便它从说明 Maven 3.0 弃用的更新开始?非常感谢!
我相信一个很好的平衡是锁定主要版本但获得最新的次要(或补丁)版本(无论哪个仅用于您所依赖的工件中的错误修复)。使用当前的语法,这似乎只能在一个范围内实现(注意:以括号开头,以括号结尾):[1.1,2.0)
FWIW...更新了指向 Maven3 兼容性说明的链接:cwiki.apache.org/confluence/display/MAVEN/…
值得注意的是,[1.0.0, 2.0.0] 范围不包括 1.0-SNAPSHOT,但确实包括 2.0-SNAPSHOT。
T
Tim

现在我知道这个话题很老了,但是阅读问题和 OP 提供的答案似乎 Maven Versions Plugin 实际上可能是他问题的更好答案:

特别是以下目标可能有用:

版本:使用最新版本在 pom 中搜索所有较新版本的版本,并用最新版本替换它们。

versions:use-latest-releases 在 pom 中搜索所有较新版本的非 SNAPSHOT 版本,并将它们替换为最新版本。

版本:更新属性更新项目中定义的属性,以便它们对应于特定依赖项的最新可用版本。如果必须将一组依赖项都锁定到一个版本,这将很有用。

还提供了以下其他目标:

versions:display-dependency-updates 扫描项目的依赖关系并生成具有更新版本可用的依赖关系的报告。

versions:display-plugin-updates 扫描项目的插件并生成具有更新版本可用插件的报告。

版本:更新父更新项目的父部分,以便它引用最新的可用版本。例如,如果您使用公司根 POM,如果您需要确保使用的是最新版本的公司根 POM,则此目标会很有帮助。

版本:更新子模块更新项目的子模块的父部分,以便版本与当前项目的版本匹配。例如,如果您有一个聚合器 pom,它也是它聚合的项目的父级,并且子级和父级版本不同步,则此 mojo 可以帮助修复子模块的版本。 (请注意,如果您的项目严重损坏以至于由于版本不匹配而无法构建,您可能需要使用 -N 选项调用 Maven 以运行此目标)。

版本:lock-snapshots 在 pom 中搜索所有 -SNAPSHOT 版本并将它们替换为该 -SNAPSHOT 的当前时间戳版本,例如 -20090327.172306-4

版本:解锁快照在 pom 中搜索所有时间戳锁定的快照版本,并用 -SNAPSHOT 替换它们。

版本:解析范围使用版本范围查找依赖项并将范围解析为正在使用的特定版本。

versions:use-releases 在 pom 中搜索所有已发布的 -SNAPSHOT 版本,并将其替换为相应的发布版本。

versions:use-next-releases 在 pom 中搜索所有较新版本的非 SNAPSHOT 版本,并用下一个版本替换它们。

versions:use-next-versions 在 pom 中搜索所有较新版本的版本,并将它们替换为下一个版本。

版本:提交删除 pom.xml.versionsBackup 文件。构成内置“穷人单片机”的一半。

版本:revert 从 pom.xml.versionsBackup 文件恢复 pom.xml 文件。构成内置“穷人单片机”的一半。

只是想我会把它包括在内以供将来参考。


在这种情况下,“发布”和“版本”有什么区别。
@BenNoland,我相信这种情况的不同之处在于下一个版本可能不需要是发布工件。例如,给定版本为 1.0.0-SNAPSHOT、1.0.0 和 1.0.1-SNAPSHOT 的工件,以及对 1.0.0-SNAPSHOT 的 pom 引用,versions:next-versions 和 versions:next-releases 将解析为 1.0.0 ,而版本:最新版本和版本:最新版本将分别解析为 1.0.1-SNAPSHOT 和 1.0.0。
打印所有可能的和不相关的目标是没有帮助的。
我正在寻找的是与版本相反的东西:resolve-ranges。我有一个已解决的 pom,我想打开新版本(即从 1.2.3-4[1.2,)
我认为versions:use-latest-versions 解决了OP 的大部分问题。
S
Simon Forsberg

请查看 this page(“依赖版本范围”部分)。你可能想做的是

<version>[1.2.3,)</version>

这些版本范围在 Maven2 中实现。


您可能想仔细查看 Maven 如何比较版本号 - 如果您不符合严格的模式,Maven 将比较为字符串而不是数字。
该页面位于 Codehaus 上,并将其自身描述为“尚未为 Maven 2.0 实现”的东西...... Maven 文档本身并没有说明版本范围。我错过了什么吗?何时引入版本范围?它们在官方文档中的描述在哪里?
你错了,版本范围意味着从 1.2.3 到更高版本的所有版本都可以。这根本不是最新版本。
M
Miss Chanandler Bong

与其他人不同,我认为您可能总是想要最新版本的原因有很多。特别是如果您正在进行持续部署(我们有时一天会发布 5 个版本)并且不想进行多模块项目。

我所做的是让 Hudson/Jenkins 为每个构建执行以下操作:

mvn clean versions:use-latest-versions scm:checkin deploy -Dmessage="update versions" -DperformRelease=true

那就是我使用版本插件和 scm 插件来更新依赖项,然后将其签入源代码控制。是的,我让我的 CI 进行 SCM 签入(对于 maven 发布插件,无论如何您都必须这样做)。

您需要将版本插件设置为仅更新您想要的内容:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>versions-maven-plugin</artifactId>
    <version>1.2</version>
    <configuration>
        <includesList>com.snaphop</includesList>
        <generateBackupPoms>false</generateBackupPoms>
        <allowSnapshots>true</allowSnapshots>
    </configuration>
</plugin>

我使用发布插件进行发布,该发布负责处理 -SNAPSHOT 并验证是否存在 -SNAPSHOT 的发布版本(这很重要)。

如果您按照我的方式进行操作,您将获得所有快照构建的最新版本和发布构建的最新发布版本。您的构建也将是可重现的。

更新

我注意到一些评论询问了这个工作流程的一些细节。我会说我们不再使用这种方法,而 maven 版本插件存在缺陷的主要原因是,通常存在固有缺陷。

这是有缺陷的,因为要运行版本插件来调整版本,所有现有版本都需要存在才能使 pom 正确运行。也就是说,如果找不到 pom.xml 中引用的版本,则版本插件无法更新到任何东西的最新版本。这实际上很烦人,因为我们经常出于磁盘空间的原因清理旧版本。

真的,你需要一个来自 maven 的单独工具来调整版本(所以你不依赖 pom 文件来正确运行)。我已经用 Bash 这种低级语言编写了这样一个工具。该脚本将更新版本插件等版本并将 pom 检入源代码控制。它的运行速度也比 mvn 版本插件快 100 倍。不幸的是,它不是以供公众使用的方式编写的,但是如果人们有兴趣,我可以这样做并将其放在 gist 或 github 中。

回到工作流程,因为一些评论询问这就是我们所做的:

我们在他们自己的存储库中有 20 个左右的项目和他们自己的 jenkins 工作当我们发布时使用 maven 发布插件。插件的文档中介绍了其工作流程。 maven 发布插件有点糟糕(而且我很友善),但它确实有效。有一天,我们计划用更优化的方法替换这种方法。当其中一个项目发布时,jenkins 然后运行一项特殊作业,我们将调用 update all versions 作业(jenkins 如何知道它的发布是一种复杂的方式,部分原因是 maven jenkins 发布插件也很糟糕)。更新所有版本作业了解所有 20 个项目。它实际上是一个聚合器 pom,以依赖顺序指定模块部分中的所有项目。 Jenkins 运行我们的魔法 groovy/bash foo,它将拉动所有项目将版本更新到最新版本,然后签入 poms(再次根据模块部分按依赖顺序完成)。对于每个项目,如果 pom 已更改(由于某些依赖项中的版本更改),则将其签入,然后我们立即 ping jenkins 为该项目运行相应的作业(这是为了保留构建依赖项顺序,否则您将受到摆布SCM 轮询调度程序)。

在这一点上,我认为无论如何让发布和自动版本成为与您的一般构建分开的工具是一件好事。

现在您可能会因为上面列出的问题而认为 maven 有点糟糕,但是对于没有声明性易于解析可扩展语法(又名 XML)的构建工具来说,这实际上是相当困难的。

事实上,我们通过命名空间添加自定义 XML 属性来帮助提示 bash/groovy 脚本(例如,不要更新此版本)。


感谢您在回答中包含动机(持续部署)。
我认为重要的一点是,使用这种方法可以重现构建,而在使用版本范围或 -LATEST 时,它们不是!
我想在运行构建之前使用外部工具对项目 pom 进行更改来支持解决方案。我们也在使用这种方法,因为 version-range-plugin 本身就存在错误,例如考虑日期而不仅仅是版本。
任何人都可以帮助我遇到与 stackoverflow.com/questions/45179530/… 相同的问题。我在使用验证阶段的构建期间设置为执行。我可以看到版本更新,但真正的构建仍然使用旧值......
m
mkobit

依赖项语法位于 Dependency Version Requirement Specification 文档中。这是为了完整性:

依赖的版本元素定义版本要求,用于计算有效的依赖版本。版本要求具有以下语法: 1.0:对 1.0 的“软”要求(只是建议,如果它与依赖项的所有其他范围匹配)[1.0]:对 1.0 的“硬”要求(,1.0]:x <= 1.0 [ 1.2,1.3]: 1.2 <= x <= 1.3 [1.0,2.0): 1.0 <= x < 2.0 [1.5,): x >= 1.5 (,1.0],[1.2,): x <= 1.0 或 x > = 1.2;多个集合以逗号分隔 (,1.1),(1.1,):这不包括 1.1(例如,如果已知它不能与此库结合使用)

在您的情况下,您可以执行类似 <version>[1.2.3,)</version> 的操作


M
Martin Klinke

您是否可能依赖在开发过程中明显变化很大的开发版本?

您可以只使用在必要时覆盖的快照版本,而不是增加开发版本的版本,这意味着您不必在每次微小更改时更改版本标签。 1.0-SNAPSHOT 之类的东西...

但也许您正在尝试实现其他目标;)


t
trung

谁使用过 LATEST,请确保您有 -U 否则将不会提取最新的快照。

mvn -U dependency:copy -Dartifact=com.foo:my-foo:LATEST
// pull the latest snapshot for my-foo from all repositories

这不会从本地 m2 存储库中提取最新快照
V
Verhagen

事实是即使在 3.x 中它仍然有效,令人惊讶的是项目的构建和部署。但是 LATEST/RELEASE 关键字在 m2e 和 eclipse 中到处都是问题,ALSO 项目依赖于通过 LATEST/RELEASE 部署的依赖项无法识别版本。

如果您尝试将版本定义为属性,并在其他地方引用它,它也会导致问题。

所以结论是尽可能使用versions-maven-plugin


K
Kalle Richter

在提出这个问题时,maven 中的版本范围存在一些问题,但这些问题已在较新版本的 maven 中得到解决。本文很好地介绍了版本范围的工作原理和最佳实践,以更好地了解 maven 如何理解版本:https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855


虽然这在理论上可以回答问题,但it would be preferable在此处包含答案的基本部分,并提供链接以供参考。
M
Markon

有时您不想使用版本范围,因为它们似乎“缓慢”地解决您的依赖关系,尤其是在持续交付并且有大量版本的情况下 - 主要是在大量开发期间。

一种解决方法是使用 versions-maven-plugin。例如,您可以声明一个属性:

<properties>
    <myname.version>1.1.1</myname.version>
</properties>

并将versions-maven-plugin添加到您的pom文件中:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>versions-maven-plugin</artifactId>
            <version>2.3</version>
            <configuration>
                <properties>
                    <property>
                        <name>myname.version</name>
                        <dependencies>
                            <dependency>
                                <groupId>group-id</groupId>
                                <artifactId>artifact-id</artifactId>
                                <version>latest</version>
                            </dependency>
                        </dependencies>
                    </property>
                </properties>
            </configuration>
        </plugin>
    </plugins>
</build>

然后,为了更新依赖项,您必须执行目标:

mvn versions:update-properties validate

如果有比 1.1.1 更新的版本,它会告诉你:

[INFO] Updated ${myname.version} from 1.1.1 to 1.3.2

A
Arayan Singh

如果你希望Maven应该使用最新版本的依赖,那么你可以使用Versions Maven Plugin以及如何使用这个插件,Tim已经给出了很好的答案,跟随他的answer

但作为开发人员,我不会推荐这种做法。为什么?

Pascal Thivent 在问题的评论中已经给出了为什么的答案

为了构建可重复性,我真的不推荐这种做法(也不使用版本范围)。由于未知原因开始突然失败的构建比手动更新版本号更烦人。

我会推荐这种练习:

<properties>
    <spring.version>3.1.2.RELEASE</spring.version>
</properties>

<dependencies>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

</dependencies>

它易于维护和调试。您可以立即更新您的 POM。


如果您使用versions-maven-plugin,构建仍然是可重现的。更新 maven 版本可以在单独的提交中完成(从我的回答中可以看出,您必须指定一个单独的目标,它不会在构建中神奇地发生)。
y
yilin

我在 Maven 3.5.4 中的解决方案,在 Eclipse 中使用 nexus:

<dependency>
    <groupId>yilin.sheng</groupId>
    <artifactId>webspherecore</artifactId>
    <version>LATEST</version> 
</dependency>

然后在eclipse中:atl + F5,然后选择force update of snapshots/release

这个对我有用。


尽管出于上述各种帖子中明确说明的原因,但不会在命令行上工作。我们中的许多人必须符合自动化构建,因此我们的 POM 必须在命令行运行时工作,而不仅仅是在 Eclipse 中。