951

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?为什么不在需要的模块中直接定义呢?

4

14 回答 14

1034

我对这个问题的回答很晚,但我认为值得一个比接受的更清晰的回答(这是正确的,但不强调实际重要的部分,你需要自己推断)。

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

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

  • 部分中指定的工件,只有在子模块本身<dependencyManagement>的部分中也指定时才会包含在子模块中<dependencies>。你问为什么好?因为您在父 POM 中指定版本和/或范围,并且您可以在指定子 POM 中的依赖项时将它们排除在外。这可以帮助您对子模块的依赖项使用统一版本,而无需在每个子模块中指定版本。

于 2016-05-17T15:49:12.440 回答
553

依赖管理允许合并和集中管理依赖版本,而无需添加所有子代继承的依赖。当您有一组项目(即多个项目)继承了一个共同的父项目时,这尤其有用。

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

于 2010-04-12T03:31:11.633 回答
77

Maven 网站上的文档很糟糕。dependencyManagement 所做的只是将您的依赖项定义(版本、排除项等)向上移动到父 pom,然后在子 pom 中您只需放置 groupId 和 artifactId。就是这样(除了父 pom 链接等,但这也不是很复杂——dependencyManagement 胜过父级的依赖——但如果对此或导入有疑问,Maven 文档会更好一些)。

在阅读了 Maven 站点上所有的“a”、“b”、“c”垃圾并感到困惑之后,我重新编写了他们的示例。因此,如果您有 2 个项目(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>
于 2016-03-25T21:55:14.833 回答
66

在我看来,还有一件事没有得到足够的重视,那就是不必要的继承

这是一个增量示例:

我在我的parentpom 中声明:

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

繁荣!我在我的Child A,Child BChild C模块中有它:

  • 子 pom 继承的隐含性
  • 一个管理的地方
  • 无需在 child poms 中重新声明任何内容
  • 如果我愿意,version 18.0我仍然可以重新照顾和覆盖。Child B

但是,如果我最终不需要 guava Child C,将来也不Child D需要Child E模块怎么办?

他们仍然会继承它,这是不希望的! 这就像 Java God 对象代码的味道,你从一个类中继承了一些有用的位,以及大量不需要的东西。

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

而且,很明显,你不这样做Child C,因此你的模块仍然很精简。

于 2017-12-17T11:27:41.060 回答
45

就像你说的;dependencyManagement用于将所有依赖信息拉到一个通用的 POM 文件中,简化子 POM 文件中的引用。

当您不想在多个子项目下重新键入多个属性时,它会变得很有用。

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

于 2010-04-12T03:08:45.933 回答
33

对不起,我迟到了。

让我尝试使用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 guava在每个模块(包括父模块)中被列为依赖项,而apache commons仅在数据模块中被列为依赖项(甚至在父模块中也没有)

于 2019-06-19T06:06:38.783 回答
27

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

但是,下面以简洁的方式阐述了几点:

  1. <dependencyManagement>允许整合跨不同模块使用的所有依赖项(在子 pom 级别使用)——清晰集中依赖版本管理
  2. <dependencyManagement>允许根据需要轻松升级/降级依赖项,在其他情况下,这需要在每个子 pom 级别进行 -一致性
  3. 标签中提供的依赖项<dependencies>总是被导入,而<dependencyManagement>父 pom 中提供的依赖项只有在子 pom 的<dependencies>标签中有相应的条目时才会被导入。
于 2017-04-18T14:38:53.013 回答
13

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

于 2014-02-11T14:18:19.150 回答
7

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

  • 隐式依赖<dependencies>:在你的节中定义的所有依赖parent-project都被所有的继承child-projects
  • 显式依赖项:允许您选择要在child-projects. 因此,您使用该<dependencyManagement>部分来声明您将在不同的child-projects. 最重要的是,在本节中,您定义了 a<version>以便您不必在child-project.

<dependencyManagement>我看来(如果我错了,请纠正我)只是通过帮助您集中依赖项的版本而有用。它就像一种辅助功能。作为最佳实践,您<dependencyManagement>必须位于其他项目将继承的父项目中。一个典型的例子是通过声明 Spring 父项目来创建 Spring 项目的方式。

于 2019-11-20T04:22:11.013 回答
2

两者之间的区别最好体现在 Maven 网站文档中可用的 dependencyManagement 元素的必要和充分定义中:

依赖管理

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

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

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

因此,依赖元素的所有子元素(范围、排除项等)——除了 groupId、artifactId、type、classifier,而不仅仅是 version——在此时可用于锁定/默认(并因此继承自从那里开始)您在dependencyElement 中指定依赖项。如果您将 type 和 classifier 子元素的依赖项(请参阅第一个引用的网页以检查所有子元素)分别指定为 not jar 和 not null,则需要 {groupId, artifactId, classifier, type}在源自dependencyManagement 元素的继承中的任何点引用(解决)该依赖项。否则,如果您不打算覆盖分类器和类型的默认值(分别为 jar 和 null),则 {groupId, artifactId} 就足够了。所以 default 在该定义中是一个很好的关键字;任何子元素(groupId 除外,

因此,dependencyManagement 之外的任何依赖元素,无论是作为对某个dependencyManagement 元素的引用还是作为独立元素,都会立即被解析(即安装到本地存储库并且可用于类路径)。

于 2019-08-13T06:52:52.017 回答
1

在 Eclipse 中,dependencyManagement. 如果dependencies不使用它,则在 pom 文件中会注意到未找到的依赖项。如果dependencyManagement使用,未解决的依赖关系在 pom 文件中不会被注意到,错误只会出现在 java 文件中。(进口等...)

于 2013-12-18T22:54:54.307 回答
1

我不建议使用dependencyManagement.

使用它的唯一好处是您可以在父 pom 中定义版本,而无需在子 pom 中再次定义它。但是如果你有一组项目(尤其是微服务项目)。使用dependencyManagement没有任何好处。

不同的项目可能需要不同的依赖。为什么要从同一个父 pom 继承它。让它尽可能简单。如果一个项目需要一个依赖,那么将其添加到 pom 文件中。不要混淆开发人员。

于 2021-09-22T03:00:36.687 回答
0

如果你有一个 parent-pom ,那么在我看来,<dependencyManagement>仅用于控制版本(可能还有范围)是浪费空间并使初级开发人员感到困惑。

无论如何,您可能会在某种父 pom 文件中拥有版本的属性。为什么不在子 pom 中使用这个属性呢?这样,您仍然可以一次为所有子项目更新属性中的版本(在父 pom 中)。<dependencyManagement>这与没有的效果相同<dependencyManagement>

在我看来,<dependencyManagement>应该用于“真正的”依赖管理,比如排除等。

于 2020-09-01T12:22:48.810 回答
0

的一个用例<dependencyManagement>是解决库版本冲突。

例子:

  • 项目 A 有库 x:1.0.1
  • 项目 A 有 B 库
  • B 库有库 x:1.0.0

有了这个集合,你会在项目 Ax:1.0.1x:1.0.0. 要解决此问题,您可以将具有特定版本的依赖项放入<dependencyManagement>标签

于 2021-07-23T07:53:52.263 回答