Maven中dependencyManagement和依赖关系之间的区别


765

dependencyManagement和之间有什么区别dependencies?我已经在Apache Maven网站上看到了这些文档。似乎dependencyManagement可以在其子模块中使用在之下定义的依赖项,而无需指定版本。

例如:

父项目(Pro-par)在以下项下定义依赖项dependencyManagement

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

然后在Pro-par的子级中,我可以使用junit:

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

但是,我想知道是否有必要在父pom中定义junit吗?为什么不直接在所需的模块中定义它?

Answers:


463

依赖关系管理允许整合和集中管理依赖关系版本,而无需添加所有子级都继承的依赖关系。当您有一组项目(即多个项目)继承同一个父对象时,此功能特别有用。

的另一个极其重要的用例dependencyManagement是控制在传递依赖中使用的工件的版本。没有示例就很难解释。幸运的是,在文档中对此进行了说明。


17
因此,无论是否在子项目pom的<dependencyManagement>部分中声明了依赖项,都需要在子项目pom的声明中声明依赖项?是否可以对依赖进行某种继承?
johnny-b-goode 2012年

55
是的,您仍然需要在子POM中定义它们,以表明您正在使用它们。实际上,它们并不包含在子项目中,只是因为它们<dependencyManagement>在父POM中。<dependencyManagement>如果决定何时以及何时使用,则将依赖项封闭起来可以集中管理每个依赖项的版本,范围和排除项。Maven的依赖管理指南详细介绍了所有细节。
hotshot309 2012年

2
第二段(dependencyManagement当依赖性明确设置也控制传递依赖)是唯一真正:stackoverflow.com/questions/28312975/...
罗伯特·梅茨格

2
@ johnny-b-goode您仍然可以做的是dependencies在父pom中创建一个新部分。我们这样做是为了使所有子项目默认都有一些apache-commons,而不是一直声明它们。
рüффп

769

我在这个问题上已经很晚了,但是我认为这是一个比被接受的答案更明确的答案(这是正确的,但不强调您需要推论的实际重要部分)。

在父POM中,<dependencies>和之间的主要区别<dependencyManagement>是:

<dependencies>节中指定的工件将始终作为子模块的依赖项包括在内。

<dependencyManagement>如果<dependencies>在子模块本身的部分中也指定了工件,则本节中指定的工件将仅包括在子模块中。你问为什么好?因为您在父级中指定了版本和/或范围,并且可以在子级POM中指定依赖项时将其忽略。这可以帮助您将统一版本用于子模块的依赖性,而无需在每个子模块中指定版本。


1
但是,在根中使用<dependencyManagement>over 也是不是有点开销?孩子的可能要短得多。<dependencies>.pompom
珍妮丝·库哈尔(Janetz Kuhar),

18
确实如此。使用<dependencies>而不是<dependencyManagement>将创建较短的子poms。但是,这带来了成本-这意味着将始终为所有子模块定义那些依赖关系。如果只有一些子模块需要特定的依赖性,则可以使用“ <dependencyManagement>”来选择哪些子模块将具有该依赖性,并且通过仅在父pom中设置依赖性版本来提高效率。
dcoder

2
@JanezKuhar对我来说有意义的是,如果您在子模块中指定了一个依赖项,它将覆盖父项中的依赖项,但是我承认我不记得了。如果有机会,我将不得不检查Maven文档。尽管设置一个简单的父子项目并进行验证可能更容易:)
dcoder

26
一个简单概念的好解释-为什么Maven这么容易地解释自己的工具似乎如此困难?
jimmy_terra'5

1
我还要补充Artifacts specified in the <dependencies> section will ALWAYS be included as a dependency of the child module(s)一点,它们也包含在父级中。似乎无法为子级设置依赖项,但不能为父级设置依赖项。
caduceus

54

文件在Maven站点是可怕的。dependencyManagement所做的只是将依赖项定义(版本,排除项等)移动到父pom,然后在子pom中,您只需要放置groupId和artifactId。就是这样(除了父pom链之类的东西之外,但这也不是很复杂的-DependencyManagement胜过了父级的依赖关系-但是如果对此或导入有疑问,则Maven文档会更好一些)。

在阅读了Maven网站上的所有“ a”,“ b”,“ c”垃圾并感到困惑之后,我重新编写了他们的示例。因此,如果您有两个项目(proj1和proj2)共享一个公共依赖项(betaShared),则可以将该依赖项移至父pom。在使用它的同时,还可以向上移动任何其他依赖项(alpha和charlie),但前提是对您的项目有意义。因此,对于前面句子中概述的情况,这是在父pom中使用dependencyManagement的解决方案:

<!-- ParentProj pom -->
<project>
  <dependencyManagement>
    <dependencies>
      <dependency> <!-- not much benefit defining alpha here, as we only use in 1 child, so optional -->
        <groupId>alpha</groupId>
        <artifactId>alpha</artifactId>
        <version>1.0</version>
        <exclusions>
          <exclusion>
            <groupId>zebra</groupId>
            <artifactId>zebra</artifactId>
          </exclusion>
        </exclusions>
      </dependency>
      <dependency>
        <groupId>charlie</groupId> <!-- not much benefit defining charlie here, so optional -->
        <artifactId>charlie</artifactId>
        <version>1.0</version>
        <type>war</type>
        <scope>runtime</scope>
      </dependency>
      <dependency> <!-- defining betaShared here makes a lot of sense -->
        <groupId>betaShared</groupId>
        <artifactId>betaShared</artifactId>
        <version>1.0</version>
        <type>bar</type>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
</project>

<!-- Child Proj1 pom -->
<project>
  <dependencies>
    <dependency>
      <groupId>alpha</groupId>
      <artifactId>alpha</artifactId>  <!-- jar type IS DEFAULT, so no need to specify in child projects -->
    </dependency>
    <dependency>
      <groupId>betaShared</groupId>
      <artifactId>betaShared</artifactId>
      <type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
    </dependency>
  </dependencies>
</project>

<!-- Child Proj2 -->
<project>
  <dependencies>
    <dependency>
      <groupId>charlie</groupId>
      <artifactId>charlie</artifactId>
      <type>war</type> <!-- This is not a jar dependency, so we must specify type. -->
    </dependency>
    <dependency>
      <groupId>betaShared</groupId> 
      <artifactId>betaShared</artifactId> 
      <type>bar</type> <!-- This is not a jar dependency, so we must specify type. -->
    </dependency>
  </dependencies>
</project>

2
有点离题的问题:依赖项类型“ bar”是什么意思?我在Maven文档的示例pom中看到了,但是找不到定义。我以为这是“战争”或“罐子”的错字,但我在其他示例(例如您的示例)中看到了。
NobodyMan '16

NobodyMan-因此,它只是另一种存档类型的占位符。就像使用'foo'。或者,如果有人使用扩展名“ bar”创建自定义类型,则可以使用它。而且还有很多晦涩的存档类型。就像sar,它是jboss服务档案。
MattC '16

您的示例非常清楚,并重申了我自己从文档中得出的结论。您是否已将其提交到Maven项目?研究完您的示例后,我准备简化同时具有二者且仅需要依赖项声明的POM,因为与其关联的项目没有子代。
大卫·A·格雷

好吧,我打算删除DependencyManagement节点,直到我想到离开它使我能够为间接找到依赖关系树的所有子POM建立最低版本。举例来说,在追踪javax.cache.cache-apI时,我发现了一个明显较新的版本1.0.0(相对于0.3.0),该版本也可以在整个版本中使用。
大卫·A·格雷

这种解释是完美的。
Smart Coder

45

就像你说的 dependencyManagement用于将所有依赖项信息提取到公共POM文件中,从而简化了子POM文件中的引用。

当您有多个不想在多个子项目中重新输入的属性时,此功能将非常有用。

最后,dependencyManagement可用于定义工件的标准版本以在多个项目中使用。


4
那么,依赖项不会继承吗?无论如何,它需要在子项目的pom中声明吗?
johnny-b-goode 2012年

6
是的,无论如何,您都需要在子项目中声明它们,但无需指定版本。
帕维尔·弗拉索夫

当您想对具有父子关系的多个Java项目中的版本进行管理时,此方案很有用。
阿努伊·库玛

43

在我看来,还有一件事情没有被充分强调,那就是不需要的继承

这是一个增量示例:

我在parentpom中声明:

<dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
</dependencies>

繁荣!我有它在我Child AChild BChild C模块:

  • 儿童poms继承的违规行为
  • 一个地方管理
  • 无需在子poms中重新声明任何内容
  • 我仍然可以redelcare并覆盖到version 18.0Child B,如果我想。

但是,如果我最终什么不需要番石榴Child C,也不对未来Child DChild E模块?

他们仍然会继承它,这是不希望的! 就像Java God Object代码的味道一样,您可以从类中继承一些有用的位,还可以继承大量不需要的东西。

这就是<dependencyManagement>发挥作用的地方。将其添加到父pom时,所有子模块都停止看到它。因此,您被迫进入确实需要它的每个模块,并再次声明它(Child A并且Child B,尽管没有版本)。

而且,很显然,您没有为此做准备Child C,因此您的模块保持精益。


对于父pom项目,<dependencyManagement>中提到的依赖项是否会下降?
Jaspreet Jolly

您确定如果我们<dependencyManagement>在父pom中使用它,那么默认情况下依赖项将不会在子pom中继承?因为在doc:maven.apache.org/guides/introduction/…中,在解释其第二次使用时,<dependencyManagement>它看起来像是默认继承的。他们在一行上说:“当在项目B上运行maven时,将使用工件a,b,c和d的版本1.0,而不考虑其pom中指定的版本”,即使在项目b中未使用“ b”项目B
chirag soni

自己尝试一下
Andrejs

17

有一些答案概述了Maven <depedencies><dependencyManagement>标签之间的区别。

但是,以下几点简明扼要:

  1. <dependencyManagement>允许合并跨不同模块使用的所有依赖项(在子pom级别使用)- 清晰集中的依赖项版本管理
  2. <dependencyManagement>允许根据需要轻松升级/降级依赖关系,在其他情况下,则需要在每个子pom级别上进行锻炼- 一致性
  3. <dependencies>标签中提供的依赖项始终会导入,而<dependencyManagement>父pom中提供的依赖项只有在子pom的<dependencies>标签中具有相应条目时才会导入。

17

抱歉,我晚会很晚。

让我尝试使用mvn dependency:tree命令来解释差异

考虑下面的例子

父POM-我的项目

<modules>
    <module>app</module>
    <module>data</module>
</modules>

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>19.0</version>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
    </dependencies>
</dependencyManagement>

子POM-数据模块

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>

子POM-应用程序模块(没有额外的依赖性,因此将依赖性保留为空)

 <dependencies>
</dependencies>

在运行mvn dependency:tree命令时,我们得到以下结果

Scanning for projects...
------------------------------------------------------------------------
Reactor Build Order:

MyProject
app
data

------------------------------------------------------------------------
Building MyProject 1.0-SNAPSHOT
------------------------------------------------------------------------

--- maven-dependency-plugin:2.8:tree (default-cli) @ MyProject ---
com.iamvickyav:MyProject:pom:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile

------------------------------------------------------------------------
Building app 1.0-SNAPSHOT
------------------------------------------------------------------------

--- maven-dependency-plugin:2.8:tree (default-cli) @ app ---
com.iamvickyav:app:jar:1.0-SNAPSHOT
\- com.google.guava:guava:jar:19.0:compile

------------------------------------------------------------------------
Building data 1.0-SNAPSHOT
------------------------------------------------------------------------

--- maven-dependency-plugin:2.8:tree (default-cli) @ data ---
com.iamvickyav:data:jar:1.0-SNAPSHOT
+- org.apache.commons:commons-lang3:jar:3.9:compile
\- com.google.guava:guava:jar:19.0:compile

Google番石榴在每个模块(包括父模块)中被列为依赖项,而apache commons仅在数据模块(甚至在父模块中)中列为依赖项


11

如果依赖项是在顶级pom的dependencyManagement元素中定义的,则子项目不必显式列出依赖项的版本。如果子项目确实定义了一个版本,它将覆盖顶级POM的dependencyManagement部分中列出的版本。即,仅在子代未直接声明版本时才使用dependencyManagement版本。


1
我相信这句话可能是不正确的。在Maven的依赖关系管理示例(#2)中,他们说在父pom中定义的具有版本的依赖关系将覆盖子pom中指定的版本: ,无论pom中指定的版本如何,都将使用d。”
devdanke 2015年

@devdanke至少,Eclipse m2e发出警告:为...覆盖托管版本
GeroldBroser恢复了Monica's

4

在父POM中,<dependencies>和之间的主要区别 <dependencyManagement>是:

<dependencies>节中指定的工件将始终作为子模块的依赖项包括在内。

如果在子模块本身的部分中也指定了工件,则本节中指定的工件将仅包括在子模块中。你问为什么好?因为您在父级中指定了版本和/或范围,并且可以在子级POM中指定依赖项时将其忽略。这可以帮助您将统一版本用于子模块的依赖性,而无需在每个子模块中指定版本。


4

用我自己的话说,您parent-project可以帮助您提供两种依赖:

  • 隐式依赖项<dependencies>您的部分中定义的所有依赖项parent-project都被所有child-projects
  • 显式依赖项:允许您选择要在中应用的依赖项child-projects。因此,您可以使用该<dependencyManagement>部分声明要在different中使用的所有依赖项child-projects。最重要的是,在本节中,您定义了一个,<version>因此您不必在中再次声明它child-project

<dependencyManagement>在我的观点(纠正我,如果我错了)只是帮助你集中你的依赖关系的版本是有用的。这就像一种辅助功能。


1

在Eclipse中,中的另一个功能dependencyManagement。如果dependencies不使用它,则在pom文件中会发现未找到的依赖项。如果dependencyManagement使用,则未解决的依赖项在pom文件中不会被注意到,并且错误仅在java文件中出现。(进口等)


1

最好将两者之间的区别引入Maven网站文档中提供的dependencyManagement元素的必要定义和充分定义:

依赖管理

“继承自此项目的项目的默认依赖关系信息。本节中的依赖关系不会立即得到解决。相反,当从此项目派生的POM声明由匹配的groupId和artifactId描述的依赖项时,版本和本节中的其他值如果尚未指定,则用于该依赖项。” [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]

应该将其与其他页面上的更多信息一起阅读:

“ ..用于将依赖项引用与dependencyManagement部分进行匹配的最小信息集实际上是{groupId,artifactId,type,classifier}。在许多情况下,这些依赖项将引用没有分类器的jar工件。由于类型字段的默认值为jar,默认分类器为null,因此这使我们可以简化设置为{groupId,artifactId}的标识。” [ https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]

因此,依赖项的所有子元素(作用域,排除项等)(除了groupId,artifactId,类型,分类器,而不仅是版本)都可以在该点进行锁定/默认设置(并由此继承)在此之后),您可以在dependencyElement中指定依赖项。如果您将类型和分类器子元素指定为依赖项(请参阅第一个引用的网页以检查所有子元素)分别为jar和not null,则需要{groupId,artifactId,classifier,type}引用(解析)该依赖关系,该依赖关系在依赖项中的任何时候都源自dependencyManagement元素。否则,如果您不打算覆盖分类器和类型的默认值(分别为jar和null),则{groupId,artifactId}就足够了。因此,default是该定义中的一个好关键字。任何子元素(groupId除外,

因此,无论是作为dependencyManagement元素的引用还是作为独立的依赖项,在dependencyManagement之外的任何依赖项元素都将立即得到解决(即,安装到本地存储库中并且可用于类路径)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.