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


当前回答

对不起,我迟到了。

让我尝试使用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

谷歌guava在每个模块(包括父模块)中都被列为依赖项,而apache commons仅在数据模块中被列为依赖项(甚至不在父模块中)

其他回答

The documentation on the Maven site is horrible. What dependencyManagement does is simply move your dependency definitions (version, exclusions, etc) up to the parent pom, then in the child poms you just have to put the groupId and artifactId. That's it (except for parent pom chaining and the like, but that's not really complicated either - dependencyManagement wins out over dependencies at the parent level - but if have a question about that or imports, the Maven documentation is a little better).

After reading all of the 'a', 'b', 'c' garbage on the Maven site and getting confused, I re-wrote their example. So if you had 2 projects (proj1 and proj2) which share a common dependency (betaShared) you could move that dependency up to the parent pom. While you are at it, you can also move up any other dependencies (alpha and charlie) but only if it makes sense for your project. So for the situation outlined in the prior sentences, here is the solution with dependencyManagement in the parent pom:

<!-- 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>

我不建议使用dependencyManagement。

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

不同的项目可能需要不同的依赖关系。为什么要从同一个父pom继承它。尽可能保持简单。如果一个项目需要A依赖项,则将其添加到pom文件中。不要让开发人员感到困惑。

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

下面是一个增量的例子:

我在父母的遗言中声明:

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

繁荣!我把它放在我的子A、子B和子C模块中:

由子poms继承的隐式 一个单独的地方来管理 不需要在child pooms中重新声明任何内容 如果我想,我仍然可以在子B中重新调用和覆盖到18.0版本。

但是,如果我最终在Child C中不需要番石榴,在未来的Child D和Child E模块中也不需要番石榴呢?

他们仍然会继承它,这是不希望的! 这就像Java的God Object代码一样,从类中继承了一些有用的部分,同时也继承了大量不需要的东西。

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

显然,您不会为Child C这样做,因此您的模块仍然是精简的。

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

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

如果你无论如何都有一个parent-pom,那么在我看来,使用<dependencyManagement>只是为了控制版本(可能还有范围)是一种浪费空间的行为,而且会让初级开发人员感到困惑。

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

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