【问题标题】:dependencyManagement and scope依赖管理和范围
【发布时间】:2013-02-19 16:57:13
【问题描述】:

我通常将<dependencyManagement> 部分放在parent-project/pom.xml 中。这个<dependencyManagement> 部分包含我的子模块的所有依赖项的声明和版本(即没有<scope> 元素):

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
    </dependency>
  </dependencies> 
</dependencyManagement>

在所有子模块(即 moduleX/pom.xml)中,我有:

  <dependencies>
    <dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <scope>test</scope>
    </dependency>
  </dependencies> 

显然,在此示例中,我为同一个依赖项重复&lt;scope&gt;test&lt;/scope&gt; 多次(在每个需要 junit 的子模块中一次)。

我的问题是:
关于&lt;scope&gt; 声明的最佳实践是什么?
把它放在&lt;dependencyManagement&gt;中会更好吗?
还是将它放在子模块的&lt;dependencies&gt; 部分更好(就像在这篇文章中一样)?为什么?
这个问题有确定的答案吗?

【问题讨论】:

    标签: maven dependency-management


    【解决方案1】:

    聚会有点晚了,但我会加两分钱。

    我最近遇到了一个非常难以调试的问题。
    我有一个父 pom 用于管理跨多个项目的依赖项。我设置了它们之间常见的所有依赖项,包括groupIdartifactIdversion最常见的scope
    我的想法是,如果它符合最常见的scope,我就不必在每个项目的实际依赖部分中包含范围。
    当其中一些依赖项显示为传递依赖项时,就会出现问题。例如,如果:

    • A 在编译范围内依赖于 B。
    • B 在编译范围内依赖于 C。
    • C 设置为在父级的dependencyManagement 中提供。

    那么确定提供了A对C的传递依赖。我不确定这是否有意义,但这确实令人困惑。

    无论如何,省去你的麻烦,把scope从你的dependencyManagement中去掉。

    【讨论】:

    【解决方案2】:

    dependencyManagement 只是在这里定义所有项目子模块的依赖版本,本节中唯一相关的范围是 import 用于 BOM。

    必须在dependencies 部分中定义范围。

    (对于给定的依赖,它决定了使用上下文。它只允许在需要执行时包含依赖。例如,ear 不会与 Java-ee 依赖打包在一起(范围 provided)因为它会在目标服务器上找到它们。)

    [编辑]

    第一条语句有一个异常,dependencyManagement 部分中的范围 provided 将覆盖 dependencies 部分中定义的范围。见DependencyManagement to force scope

    【讨论】:

    • “本节中唯一相关的范围是导入”是否意味着如果我将范围 test 放在 dependendcyManagement 中:它没有效果?
    • 事实上,我似乎并不完全正确。 maven.40175.n5.nabble.com/…dependencyManagement范围有兴趣
    【解决方案3】:

    与其他答案一样,最佳实践是从dependencyManagement 中排除范围,并在定义依赖项时明确指定它。极少数情况下,您希望在不同范围内使用相同依赖项的不同版本,例如,在编译应用程序时使用一个版本,而在运行应用程序时使用不同版本——我能想到的唯一情况是您想显式运行您的测试不同版本的库,以防用户使用该版本而不是您指定的版本。

    如果您在dependencyManagement 中定义范围,它将将该版本的使用限制为仅定义的范围——因此任何其他范围都将选择依赖项的随机版本。我昨天在dependencyManagement中定义了junit 4.12时遇到了这个问题,但是我们的通用测试框架模块使用的是带有编译范围的junit,所以它选择了4.8.2版本。

    【讨论】:

      【解决方案4】:

      对于任何范围,将单个依赖项添加到依赖项管理中没有任何好处。你所拥有的只是复制品。如果您希望版本可配置,请添加一个属性并在您的依赖项中使用它:

      <properties>
              <junit.version>4.10</junit.version> 
          ...
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>${junit.version}</version>
          </dependency>
      </dependencies>
      

      但是,在某些情况下,依赖管理会大放异彩 - 当您使用 boms 来编排更大的工件集合的版本时,例如使用特定版本的 Java EE 实现:

      <dependencyManagement>
          <dependencies>
              <dependency>
                  <groupId>org.jboss.bom</groupId>
                  <artifactId>jboss-javaee-6.0-with-tools</artifactId>
                  <version>${javaee6.with.tools.version}</version>
                  <type>pom</type>
                  <scope>import</scope>
              </dependency>
      ....
      

      【讨论】:

      • dependencyManagement(即使只有一个依赖项)是定义工件版本的唯一位置。在我看来,这唯一的事实就足以使用它。使用属性很有用,因为您有多个始终具有相同 versionId 的工件(例如 spring 模块)
      • 使用dependencyManagement 的另一个原因是集中排除不需要的传递依赖项。
      • 使用版本属性的另一个原因是,您可以使用mvn versions:display-property-updates 快​​速检查依赖版本更新——只要您注意以artifactId.version 模式命名您的版本属性