如何告诉 Maven 使用最新版本的依赖项?
-
09-06-2019 - |
题
在Maven中,依赖关系通常是这样设置的:
<dependency>
<groupId>wonderful-inc</groupId>
<artifactId>dream-library</artifactId>
<version>1.2.3</version>
</dependency>
现在,如果您正在使用频繁发布的库,不断更新 <version> 标记可能会有些烦人。有没有办法告诉 Maven 始终使用最新的可用版本(来自存储库)?
解决方案
笔记:
这个答案仅适用于 Maven 2!其中提到的 LATEST
和 RELEASE
元版本 “为了可重现的构建”,已在 Maven 3 中被删除, ,6年多前。请参考这个 Maven 3 兼容解决方案.
如果您始终想使用最新版本,Maven 有两个关键字可以用来替代版本范围。您应该谨慎使用这些选项,因为您不再控制您正在使用的插件/依赖项。
当您依赖插件或依赖项时,可以使用 LATEST 或 RELEASE 的版本值。LATEST 是指特定工件的最新发布版本或快照版本,即特定存储库中最近部署的工件。RELEASE 指存储库中的最后一个非快照版本。一般来说,设计依赖于工件的非特定版本的软件并不是最佳实践。如果您正在开发软件,为了方便起见,您可能希望使用 RELEASE 或 LATEST,以便在发布新版本的第三方库时不必更新版本号。当您发布软件时,您应该始终确保您的项目依赖于特定版本,以减少您的构建或项目受到不受您控制的软件版本影响的机会。如果有的话,请谨慎使用 LATEST 和 RELEASE。
请参阅 Maven 书中的 POM 语法部分 更多细节。或者查看此文档 依赖项版本范围, , 在哪里:
- 方括号 (
[
&]
)指“关闭”(包括在内)。 - 括号(
(
&)
) 表示“开放”(独占)。
这是一个说明各种选项的示例。在 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>
如果需要对该工件的依赖,您有以下选项(其他 版本范围 当然可以指定,这里只显示相关的):
声明确切的版本(始终解析为 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>
将版本声明为最新(将解析为 2.0.0)(从 maven 3.x 中删除)
<version>LATEST</version>
将版本声明为 RELEASE(将解析为 1.1.1)(从 maven 3.x 中删除):
<version>RELEASE</version>
请注意,默认情况下,您自己的部署将更新 Maven 元数据中的“最新”条目,但要更新“发布”条目,您需要从 Maven超级POM. 。您可以使用“-Prelease-profile”或“-DperformRelease=true”来执行此操作
值得强调的是,任何允许 Maven 选择依赖项版本(LATEST、RELEASE 和版本范围)的方法都可能让您面临构建时间问题,因为更高版本可能有不同的行为(例如,依赖项插件之前已切换了默认值)值从 true 到 false,结果令人困惑)。
因此,在发行版中定义确切的版本通常是一个好主意。作为 蒂姆的回答 指出, maven 版本插件 是一个用于更新依赖版本的方便工具,特别是 版本:使用最新版本 和 版本:使用最新版本 目标。
其他提示
现在我知道这个话题已经很老了,但是阅读问题和OP提供的答案似乎是 Maven 版本插件 实际上可能是对他的问题的更好答案:
特别是以下目标可能有用:
- 版本:使用最新版本 在 POM 中搜索所有版本 这是较新的版本和 用最新的替换它们 版本。
- 版本:使用最新版本 在 pom 中搜索所有非 SNAPSHOT 更新的版本 释放并将它们替换为 最新版本。
- 版本:更新属性 更新中定义的属性 项目,以便它们对应于 最新版本 特定依赖项。这可以是 如果一组依赖项很有用 必须全部锁定到一个版本。
还提供了以下其他目标:
- 版本:显示依赖项更新 扫描项目的依赖项和 生成一份报告 具有较新的依赖项 提供版本。
- 版本:显示插件更新 扫描项目的插件和 生成这些插件的报告 有更新的版本可用。
- 版本:更新父级 更新项目的父部分,以便 它引用了最新的 可用版本。例如,如果 您使用企业根 POM,这 如果需要,目标可能会有所帮助 确保您使用的是最新的 企业根 POM 的版本。
- 版本:更新子模块 更新 项目的子模块,因此 version 与 当前项目。例如,如果你 有一个聚合器 POM,它也是 它的项目的父级 聚合和子项和 父版本不同步,这 Mojo 可以帮助修复 子模块。(请注意,您可能需要 使用 -N 选项调用 Maven 为了运行这个目标,如果你的 项目损坏得如此严重,以至于它 由于版本原因无法构建 不匹配)。
- 版本:锁定快照 在 pom 中搜索所有 -SNAPSHOT 版本,并将它们替换为 该版本的当前时间戳版本 -快照,例如-20090327.172306-4
- 版本:解锁快照 在 POM 中搜索所有时间戳 锁定的快照版本和替换 他们与 -SNAPSHOT.
- 版本:解析范围 使用版本范围查找依赖项,并 将范围解析为特定的 正在使用的版本。
- 版本:使用版本 在 pom 中搜索所有 -SNAPSHOT 版本 已发布并替换 它们具有相应的版本 版本。
- 版本:使用下一个版本 在 pom 中搜索所有非 SNAPSHOT 更新的版本 释放并将它们替换为 下一个发布版本。
- 版本:使用下一个版本 在 POM 中搜索所有版本 这是较新的版本和 将它们替换为下一个版本。
- 版本:提交 删除 pom.xml.versionsBackup 文件。形成内置的“穷人SCM”的一半。
- 版本:恢复 从 POM.xml 文件恢复 pom.xml.versions备份文件。形式 内置“穷人”的一半 SCM”。
只是想我会把它包括在内以供将来参考。
与其他人不同,我认为您可能有很多原因 总是想要最新的 版本。特别是如果您正在进行持续部署(我们有时一天内发布 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 versions 插件快 100 倍。不幸的是,它不是以供公众使用的方式编写的,但如果人们感兴趣,我可以这样做并将其放在 gist 或 github 中。
回到工作流程,因为一些评论询问这就是我们所做的:
- 我们在自己的存储库中有 20 个左右的项目,有自己的詹金斯工作
- 当我们发布的时候会使用maven发布插件。插件的文档中介绍了其工作流程。Maven 发布插件有点糟糕(我很友善),但它确实有效。有一天,我们计划用更优化的方法替换这种方法。
- 当其中一个项目发布时,jenkins 运行一项特殊作业,我们将调用更新所有版本作业(jenkins 如何知道它的版本是一种复杂的方式,部分原因是 Maven jenkins 发布插件也非常糟糕)。
- 更新所有版本作业了解所有 20 个项目。它实际上是一个聚合器 pom,用于按依赖顺序指定模块部分中的所有项目。Jenkins 运行我们神奇的 groovy/bash foo,它会将所有项目更新到最新版本,然后签入 poms(再次根据模块部分按依赖顺序完成)。
- 对于每个项目,如果 pom 已更改(由于某些依赖项中的版本更改),则将其签入,然后我们立即 ping jenkins 以运行该项目的相应作业(这是为了保留构建依赖项顺序,否则您将受到怜悯SCM 轮询调度程序)。
在这一点上,我认为无论如何,将发布版和自动版作为独立于常规构建的工具是一件好事。
现在你可能会认为 Maven 有点糟糕,因为上面列出的问题,但对于没有易于解析的声明性的构建工具来说,这实际上是相当困难的 可扩展的 语法(又名 XML)。
事实上,我们通过命名空间添加自定义 XML 属性来帮助提示 bash/groovy 脚本(例如不要更新此版本)。
依赖语法位于 依赖项 版本 要求 规范 文档。这是为了完整性:
依赖关系'
version
元素定义版本要求,用于计算有效的依赖版本。版本要求具有以下语法:
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>
您是否可能依赖于在开发过程中明显变化很大的开发版本?
您可以只使用必要时覆盖的快照版本,而不是增加开发版本的版本,这意味着您不必在每次细微更改时更改版本标记。类似于 1.0-SNAPSHOT...
但也许你正在尝试实现其他目标;)
谁正在使用最新的,请确保您有 -U 否则最新的快照将不会被拉取。
mvn -U dependency:copy -Dartifact=com.foo:my-foo:LATEST
// pull the latest snapshot for my-foo from all repositories
提出这个问题时,maven 中的版本范围存在一些问题,但这些问题已在较新版本的 maven 中得到解决。本文很好地捕捉了版本范围的工作原理和最佳实践,以更好地理解 Maven 如何理解版本: https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855
事实上,即使在 3.x 中它仍然有效,令人惊讶的是项目的构建和部署。但是 LATEST/RELEASE 关键字导致 m2e 和 eclipse 到处出现问题,而且项目依赖于通过 LATEST/RELEASE 部署的依赖项,无法识别版本。
如果您尝试将版本定义为属性,并在其他地方引用它,它也会导致问题。
所以结论是使用 版本-maven-插件 如果可以的话。
有时您不想使用版本范围,因为它们似乎解决您的依赖关系“缓慢”,特别是当持续交付到位并且有大量版本时 - 主要是在繁重的开发期间。
一种解决方法是使用 版本-maven-插件. 。例如,您可以声明一个属性:
<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
如果你希望 Maven 应该使用最新版本的依赖项,那么你可以使用 版本 Maven 插件 以及如何使用这个插件,Tim 已经给出了很好的答案,请关注他的 回答.
但作为一名开发人员,我不会推荐这种做法。为什么?
为什么已经给出了答案 帕斯卡·蒂文特 在问题的评论中
我真的不建议这种做法(也不使用版本范围) 为了构建可重复性。突然开始的构建 由于未知原因失败比手动更新更烦人 版本号。
我会推荐这种类型的练习:
<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。
我在maven 3.5.4中的解决方案,使用nexus,在eclipse中:
<dependency>
<groupId>yilin.sheng</groupId>
<artifactId>webspherecore</artifactId>
<version>LATEST</version>
</dependency>
然后在日食中: atl + F5
, ,并选择 force update of snapshots/release
这个对我有用。