3

在一个 Maven 项目中,我们使用了第三方工件(特别是 spring-data-jpa 1.1.0.RELEASE),它依赖于另一个工件(spring-core),允许范围内的任何版本(准确地说:[3.0.7 .RELEASE,4.0.0.RELEASE),查看它的 pom 文件)。我们没有直接依赖于 spring-core。

所以有一天我们的构建选择了 3.1.2.RELEASE,但是当 3.2.0.RC1 发布时,我们的构建突然选择了那个版本。

然而,我们希望有可重复的构建:当我们在一年的时间内交付一个补丁时,我们不想在至少不知道的情况下引入更新版本的 spring-core 或任何其他间接依赖项。

(我知道我们可以指导 Maven 为 spring-core 选择一个特定的版本,例如 using <dependencyManagement>,但我的意思是,间接依赖中可能隐藏着任意选择,我希望 Maven 告诉我们这些,无需定期手动检查。)

问题:如果 Maven 为任何间接依赖项做出任意版本选择,我们如何让 Maven 警告我们?

4

1 回答 1

2

正如您所发现的,版本范围是邪恶的。

真正的问题是版本范围是一个警笛,诱使人们认为他们是一个好主意。

版本范围确实应该被视为对开发人员的提示,以允许开发人员从一组版本中选择他们想要的版本。

Maven 中的错误在于首先允许在其中定义版本范围,pom.xml因为这允许人们发布他们的工件,其中包含版本范围。

一旦您依赖于具有使用版本范围的传递依赖项的工件,实际上只有两种方法可以解决您的构建问题(一种只是第二种的更花哨的版本)

  1. 在传递依赖项上添加您自己的依赖项,但使用固定版本代替范围......例如

    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-jpa</artifactId>
      <version>1.1.0.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>3.1.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>3.1.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>3.1.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>3.1.2.RELEASE</version>
      <exclusions>
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    

    您不需要列出依赖项,因为它们不具有传递性,同样出于同样的原因,<optional>true</optional>您也不需要列出依赖项。<scope>provided</scope>

  2. 至于上述,但首先通过向依赖项添加排除项来更安全,例如

    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-jpa</artifactId>
      <version>1.1.0.RELEASE</version>
      <exclusions>
        <exclusion>
          <groupId>org.springframework</groupId>
          <artifactId>spring-orm</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>3.1.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>3.1.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>3.1.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>3.1.2.RELEASE</version>
      <exclusions>
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    

在这两者中,我更喜欢后者,因为它至少给人们一个暗示,为什么要明确提到这些依赖关系。

所以回到你原来的问题,关键是当你在你的pom.xml.

如果spring-data-jpa:1.1.1.RELEASE有一个具有不同坐标的完全不同的传递依赖树,那么当您编辑pom.xml以更新版本时,您还应该修复传递。

据我所知,目前没有任何强制执行规则来支持验证您的要求。

我建议编写一个执行者规则,我称之为:ensureTransitiveVersionRangesArePinned

该规则应执行以下操作:

  • 扫描项目依赖列表
  • 计算每个项目依赖提供的传递依赖
  • 如果这些传递依赖项中的任何一个是版本范围,那么
    • 验证该exclusion传递依赖是否存在
    • 验证传递依赖项的固定版本是否作为直接项目依赖项(如果没有固定版本,则可能不会失败,因为您可能正在添加位于不同 GAV 的等效工件,或者您可能不需要依赖项)...在任何情况下,如果没有重新添加依赖项,单元测试很可能应该通过触发 CNFE 来捕获它,因此这个检查可能不是严格要求的,但它可能应该打印一个警告。

我不记得是否有工具可以检查它们<exclusions>是否实际上排除了任何传递依赖项,因此您可能需要对此进行调查。

于 2013-04-30T09:44:20.633 回答