在Maven中dependencyManagement和依赖关系之间的差异

hgu*_*ser 691 dependency-management pom.xml maven

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

例如:

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

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8</version>
    </dependency>
 </dependencies>
</dependencyManagement>
Run Code Online (Sandbox Code Playgroud)

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

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </dependency>
 </dependencies>
Run Code Online (Sandbox Code Playgroud)

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

dco*_*der 683

我对这个问题的时间已经很晚了,但是我认为值得回应的是明确的回答(这是正确的,但并不强调实际的重要部分,你需要自己推断).

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

<dependencies>部分中指定的工件将始终作为子模块的依赖项包含在内.

<dependencyManagement>如果<dependencies>在子模块本身的部分中也指定了子模块,则该部分中指定的工件将仅包含在子模块中.你问为什么这么好?因为您在父项中指定了版本和/或作用域,并且在指定子POM中的依赖项时可以将它们排除在外.这可以帮助您为子模块使用统一版本的依赖项,而无需在每个子模块中指定版本.

  • 一个简单概念的好解释 - 为什么Maven很容易解释自己的工具? (18认同)
  • 确实如此.使用<dependencies>而不是<dependencyManagement>将创建一个更短的子poms.但是,它带来了成本 - 这意味着将始终为所有子模块定义这些依赖项.如果只有一些子模块需要某种依赖,那么使用"<dependencyManagement>"代替将允许您选择哪些子模块具有该依赖性,并且通过仅在父pom中设置依赖性版本仍然有点效率. (11认同)
  • 当您有 10 个、15 个或数十个项目时,父 pom 中的 dependencyManagement 的值就变得很明显,并且您需要确保它们都使用不同共享库的相同版本,而不必声明所有这些项目都使用所有那些依赖关系 (7认同)
  • 但是,在根`.pom` 中使用`&lt;dependencyManagement&gt;` 而不是`&lt;dependencies&gt;` 是不是也有点开销?孩子的“pom”可能要短得多。 (4认同)
  • 我参加聚会也迟到了,但有一个问题。对于 dependencyManagement 部分,为什么不在父级中设置属性(版本),然后在子级中仅在依赖项部分中使用该版本?为什么要在父 pom 和子 pom 中都设置它? (4认同)
  • 我会添加“&lt;dependency&gt;”部分中指定的工件将始终作为子模块的依赖项包含在内,它们也包含在父模块中。似乎不可能为孩子设置依赖关系,但不能为父母设置依赖关系。 (3认同)
  • @JanezKuhar 对我来说,如果您在子模块中指定依赖项,它将覆盖父模块中的依赖项,但我承认我不记得了。当我有机会时,我将不得不检查该文档的 Maven 文档。虽然设置一个简单的父子项目并验证可能更容易:) (2认同)
  • @DimitarVukman,因为答案不完整:它不仅仅是版本。您可能已经定义了依赖项的版本、范围甚至排除。而且,即使只是对于版本,在子 pom 中声明 GA(组、工件)而不是 GAV 也更清晰、更易于维护(V 的值是您在父级中自定义定义的值) (2认同)

Pas*_*ent 433

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

另一个非常重要的用例dependencyManagement是控制传递依赖中使用的工件版本.没有一个例子,这很难解释.幸运的是,这在文档中有说明.

  • 是的,您仍然需要在子POM中定义它们以显示您正在使用它们.它们实际上并不包含在子项目中,因为它们位于父POM中的`<dependencyManagement>`中.在"<dependencyManagement>"中包含依赖关系,在您决定使用它时,集中管理每个依赖项的版本,范围和排除项.Maven的[依赖管理指南](http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management)深入了解所有细节. (47认同)
  • 那么,即使它们在<dependencyManagement>部分的父项目的pom中声明,它还是需要在子项目pom中声明依赖项?是否有可能进行某种依赖继承? (16认同)
  • @johnny-b-goode 你仍然可以做的是在你的父 pom.xml 文件中创建一个新的 `dependencies` 部分。我们这样做是为了让所有子项目默认都有一些 apache-commons,而不是一直声明它们。 (3认同)
  • 第二段(`dependencyManagement`也控制传递依赖)仅在明确设置依赖项时才为真:http://stackoverflow.com/questions/28312975/maven-dependencymanagement-version-ignored-in-transitive-dependencies (2认同)

Mat*_*ttC 48

文件在Maven站点是可怕的.dependencyManagement所做的只是将您的依赖关系定义(版本,排除等)移动到父pom,然后在子poms中您只需要放置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>
Run Code Online (Sandbox Code Playgroud)

  • 有点离题的问题:依赖项类型“ bar”是什么意思?我在Maven文档的示例pom中看到了,但是找不到定义。我以为这是“战争”或“罐子”的错字,但我在其他示例(例如您的示例)中看到了。 (2认同)
  • NothingMan - 所以它只是另一种存档类型的占位符。就像使用“foo”一样。或者,如果有人使用扩展名“bar”创建了自定义类型,则可以使用它。还有很多晦涩难懂的档案类型。就像sar一样,它是jboss服务存档。 (2认同)

Pra*_*ran 44

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

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

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

  • 是的,你需要在子项目中声明它们,但是没有指定版本. (5认同)
  • 那么,依赖关系不会继承?它需要在子项目的pom中声明吗? (3认同)

And*_*ejs 38

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

这是一个增量示例:

我在我的parentpom中宣布:

<dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>19.0</version>
        </dependency>
</dependencies>
Run Code Online (Sandbox Code Playgroud)

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

  • 儿童poms继承的implicilty
  • 一个管理的地方
  • 没有必要重新宣布儿童poms中的任何东西
  • 如果我愿意version 18.0Child B话,我仍然可以重新审视和覆盖.

但是,如果我最终不需要番石榴Child C,未来Child DChild E模块都没有?

他们仍将继承它,这是不受欢迎的! 这就像Java God Object代码气味一样,你从类中继承了一些有用的东西,还有一些不需要的东西.

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

而且,显然,你没有这样做Child C,因此你的模块仍然是精益的.


Ana*_*ika 17

有一些答案概述了maven <depedencies><dependencyManagement>标签之间的差异.

但是,下面简要阐述的几点很简单:

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


Iam*_*yAV 12

对不起,我晚会很晚。

让我尝试使用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>
Run Code Online (Sandbox Code Playgroud)

子POM-数据模块

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>
Run Code Online (Sandbox Code Playgroud)

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

 <dependencies>
</dependencies>
Run Code Online (Sandbox Code Playgroud)

在运行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
Run Code Online (Sandbox Code Playgroud)

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


Mus*_*ven 9

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


小智 5

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

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

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


Har*_*der 5

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

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

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