依赖管理和范围

Posted

技术标签:

【中文标题】依赖管理和范围【英文标题】: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; 部分更好(就像在这篇文章中一样)?为什么? 这个问题有确定的答案吗?

【问题讨论】:

【参考方案1】:

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

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

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

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

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

【讨论】:

这很有意义,但没有很好的记录,请参阅maven.40175.n5.nabble.com/…,我在下面编辑我的答案【参考方案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 模式命名您的版本属性

以上是关于依赖管理和范围的主要内容,如果未能解决你的问题,请参考以下文章

Maven 依赖管理 -- 依赖范围

04_项目一众筹00_05Maven依赖概念,依赖范围依赖传递性依赖的原则:解决jar包冲突依赖排除统一版本管理

maven课程 项目管理利器-maven 3-7 maven依赖范围 2星

maven依赖管理

Android Gradle 插件Android 依赖管理 ③ ( dependencies 依赖配置 | Project#dependencies 函数分析 | 自定义依赖配置 )

Maven01_05_compile和test依赖范围Maven的一些依赖情况依赖冲突如果出现冲突就会采取就近原则可选依赖(optional)排除依赖(exclusions)