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

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

How do I tell Maven to use the latest version of a dependency?

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

1
2
3
4
5
<dependency>
  <groupId>wonderful-inc</groupId>
  dream-library</artifactId>
  <version>1.2.3</version>
</dependency>

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


注意:

此答案仅适用于Maven 2!提到的LATESTRELEASE转换已经在6年前在Maven 3中"为了可复制的构建"而删除。
请参阅此Maven 3兼容解决方案。

如果您始终想使用最新版本,则Maven有两个关键字可以用作版本范围的替代。您应该谨慎使用这些选项,因为您将不再控制所使用的插件/依赖项。

When you depend on a plugin or a dependency, you can use the a version value of LATEST or RELEASE. LATEST refers to the latest released or snapshot version of a particular artifact, the most recently deployed artifact in a particular repository. RELEASE refers to the last non-snapshot release in the repository. In general, it is not a best practice to design software which depends on a non-specific version of an artifact. If you are developing software, you might want to use RELEASE or LATEST as a convenience so that you don't have to update version numbers when a new release of a third-party library is released. When you release software, you should always make sure that your project depends on specific versions to reduce the chances of your build or your project being affected by a software release not under your control. Use LATEST and RELEASE with caution, if at all.

有关更多详细信息,请参阅Maven书籍的POM语法部分。或参阅有关依赖版本范围的文档,其中:

  • 方括号([])表示"已关闭"(包括)。
  • 括号(())表示"打开"(不包括)。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?><metadata>
  <groupId>com.foo</groupId>
  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):

1
<version>[1.0.1]</version>

声明一个明确的版本(除非发生冲突,否则当Maven选择一个匹配的版本时,它将始终解析为1.0.1):

1
<version>1.0.1</version>

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

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

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

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

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

1
<version>LATEST</version>

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

1
<version>RELEASE</version>

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

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

因此,在版本中定义确切版本通常是个好主意。正如Tim的回答所指出的,maven-versions-plugin是一个用于更新依赖版本的便利工具,特别是版本:use-latest-versions和versions:use-latest-releases目标。


现在我知道这个主题很旧,但是阅读问题和OP提供的答案后,看来Maven版本插件实际上可能是他的问题的更好答案:

特别是可以使用以下目标:

  • 版本:use-latest-versions在pom中搜索所有版本
    这是一个较新的版本,
    用最新的替换它们
    版。
  • 版本:use-latest-releases在pom中搜索所有非SNAPSHOT
    较新的版本
    释放并替换为
    最新发布的版本。
  • 版本:update-properties更新在
    项目,以便他们对应
    最新版本的
    特定的依赖关系。这可以
    如果一组依赖项很有用
    必须全部锁定到一个版本。

还提供了以下其他目标:

  • 版本:display-dependency-updates扫描项目的依赖关系并
    制作一份报告
    更新的依赖项
    版本可用。
  • 版本:display-plugin-updates扫描项目的插件,然后
    生成这些插件的报告
    有更新的版本可用。
  • 版本:update-parent更新项目的父部分,因此
    它引用了最新的
    可用版本。例如,如果
    你使用企业根POM,这个
    如果你需要,目标可能会有所帮助
    确保您使用的是最新的
    企业根POM的版本。
  • 版本:update-child-modules更新了
    项目的子模块,因此
    版本匹配的版本
    当前的项目。例如,如果你
    有一个聚合器pom也是
    该项目的父级
    聚合和孩子们
    父版本不同步,这
    mojo可以帮助修复版本
    子模块。 (注意你可能需要
    使用-N选项调用Maven
    为了实现此目标,如果您
    项目如此糟糕,以至于它
    由于版本而无法构建
    不匹配)。
  • 版本:lock-snapshots在pom中搜索所有-SNAPSHOT
    版本并将其替换为
    该文件的当前时间戳版本
    -SNAPSHOT,例如-20090327.172306-4
  • 版本:解锁快照在pom中搜索所有时间戳
    锁定快照版本并替换
    他们用-SNAPSHOT。
  • versions:resolve-ranges使用版本范围查找依赖项
    将范围解析为特定
    正在使用的版本。
  • 版本:use-releases在pom中搜索所有-SNAPSHOT版本
    已被释放并取代
    他们与相应的发布
    版。
  • 版本:use-next-releases在pom中搜索所有非SNAPSHOT
    版本较新
    释放并替换为
    下一个版本。
  • 版本:use-next-versions在pom中搜索所有版本
    这是一个较新的版本,
    用下一个版本替换它们。
  • versions:commit删除pom.xml.versionsBackup文件。形式
    内置的"穷人"的一半
    SCM"。
  • 版本:还原从以下位置还原pom.xml文件:
    pom.xml.versionsBackup文件。形式
    内置的"穷人"的一半
    SCM"。

我以为我会把它包含在以后的任何参考中。


请查看此页面("依赖版本范围"部分)。您可能想做的是

1
<version>[1.2.3,)</version>

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


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

我所做的是让Hudson / Jenkins为每个构建做以下事情:

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

那就是我使用版本插件和scm插件来更新依赖项,然后将其检入到源代码管理中。是的,我让我的CI执行SCM签入(无论如何,对于Maven版本插件,您都必须这样做)。

您需要设置版本插件才能更新您想要的内容:

1
2
3
4
5
6
7
8
9
10
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            versions-maven-plugin</artifactId>
            <version>1.2</version>
            <configuration>
                <includesList>com.snaphop</includesList>
                <generateBackupPoms>false</generateBackupPoms>
                true</allowSnapshots>
            </configuration>
        </plugin>

我使用发布插件来完成发布-SNAPSHOT的发布,并验证是否存在-SNAPSHOT的发布版本(这很重要)。

如果执行我的操作,则将为所有快照构建获取最新版本,为发行构建获取最新发行版本。您的构建也将是可复制的。

更新

我注意到一些评论询问了这个工作流程的一些细节。我会说我们不再使用此方法,并且为什么Maven版本插件存在错误且通常存在固有缺陷是一个很大的原因。

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

确实,您需要一个与maven不同的工具来调整版本(因此,您不必依赖pom文件即可正确运行)。我用低级语言Bash编写了这样一个工具。该脚本将更新版本插件等版本,并将pom检入源代码控制。它的运行速度比mvn版本插件快100倍。不幸的是,它不是以供公众使用的方式编写的,但是如果人们感兴趣,我可以这样做,并将其放入要点或github中。

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

  • 我们在他们自己的存储库中有20个左右的项目,他们有自己的jenkins工作
  • 当我们发布Maven发布插件时。该工作流程包含在插件的文档中。 maven发布插件很糟糕(而且我很善良)但它确实有效。有一天,我们计划用更优化的方法替换这种方法。
  • 当其中一个项目被发布时,jenkins然后运行一项特殊的工作,我们将称为更新所有版本的工作(jenkins如何知道其发布是一种复杂的方式,部分原因是maven jenkins release插件也相当糟糕)。
  • 更新所有版本的作业都知道所有20个项目。实际上,它是一个聚合器pom,它以依赖关系的顺序特定于模块部分中的所有项目。詹金斯(Jenkins)运行我们的魔术groovy / bash foo,它将把所有项目拉到最新版本,然后检入poms(再次根据模块部分以依赖顺序完成)。
  • 对于每个项目,如果pom已更改(由于某些依赖项的版本更改),则将其签入,然后我们立即ping jenkins来为该项目运行相应的工作(这是为了保留构建依赖项的顺序,否则您将大为屈服SCM轮询调度程序)。
  • 在这一点上,我认为将发布和自动版本与您的常规版本分开使用是一个好习惯。

    现在您可能会因为上面列出的问题而认为行家有点烂,但是使用没有声明式易于解析可扩展语法(又称XML)的构建工具,这实际上将相当困难。

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


    依赖关系语法位于依赖关系版本要求规范文档中。这是为了完整性:

    Dependencies' version element define version requirements, used to compute effective dependency version. Version requirements have the following syntax:

    • 1.0:"Soft" requirement on 1.0 (just a recommendation, if it matches all other ranges for the dependency)
    • [1.0]:"Hard" requirement on 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 or x >= 1.2; multiple sets are comma-separated
    • (,1.1),(1.1,): this excludes 1.1 (for example if it is known not to
      work in combination with this library)

    就您而言,您可以执行类似[1.2.3,)的操作


    您是否可能依赖于开发版本,这些版本在开发期间显然会发生很大变化?

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

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


    谁正在使用LATEST,请确保您具有-U,否则不会提取最新快照。

    1
    2
    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


    有时你不想使用版本范围,因为它们似乎"慢"来解决你的依赖关系,特别是当有持续交付并且有大量版本时 - 主要是在大量开发期间。

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

    1
    2
    3
    <properties>
        <myname.version>1.1.1</myname.version>
    </properties>

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                versions-maven-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <properties>
                        <property>
                            <name>myname.version</name>
                            <dependencies>
                                <dependency>
                                    <groupId>group-id</groupId>
                                    artifact-id</artifactId>
                                    <version>latest</version>
                                </dependency>
                            </dependencies>
                        </property>
                    </properties>
                </configuration>
            </plugin>
        </plugins>
    </build>

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

    1
    mvn versions:update-properties validate

    如果版本高于1.1.1,它会告诉您:

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

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

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

    所以结论是使用versions-maven-plugin,如果可以的话。


    我的解决方案在maven 3.5.4中,在eclipse中使用nexus:

    1
    2
    3
    4
    5
    <dependency>
        <groupId>yilin.sheng</groupId>
        webspherecore</artifactId>
        <version>LATEST</version>
    </dependency>

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

    这个对我有用。


    如果您希望Maven使用最新版本的依赖项,则可以使用Versions Maven插件以及如何使用此插件,Tim已经给出了很好的答案,请遵循他的答案。

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

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

    I really don't recommend this practice (nor using version ranges) for
    the sake of build reproducibility. A build that starts to suddenly
    fail for an unknown reason is way more annoying than updating manually
    a version number.

    我将推荐这种做法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <properties>
        <spring.version>3.1.2.RELEASE</spring.version>
    </properties>

    <dependencies>

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

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

    </dependencies>

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


    推荐阅读