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


当前回答

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

dependencyManagement

从此继承的项目的默认依赖项信息。此部分中的依赖项不会立即解析。相反,当从这个POM派生的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]

Thus, all the sub-elements (scope, exclusions etc.,) of a dependency element--other than groupId, artifactId, type, classifier, not just version--are available for lockdown/default at the point (and thus inherited from there onward) you specify the dependency within a dependencyElement. If you’d specified a dependency with the type and classifier sub-elements (see the first-cited webpage to check all sub-elements) as not jar and not null respectively, you’d need {groupId, artifactId, classifier, type} to reference (resolve) that dependency at any point in an inheritance originating from the dependencyManagement element. Else, {groupId, artifactId} would suffice if you do not intend to override the defaults for classifier and type (jar and null respectively). So default is a good keyword in that definition; any sub-element(s) (other than groupId, artifactId, classifier and type, of course) explicitly assigned value(s) at the point you reference a dependency override the defaults in the dependencyManagement element.

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

其他回答

如果依赖项是在顶级pom的dependencyManagement元素中定义的,子项目就不必显式地列出依赖项的版本。如果子项目确实定义了一个版本,它将覆盖顶层中列出的版本 POM的依赖管理部分。也就是说,dependencyManagement版本仅为 当子进程没有直接声明版本时使用。

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>

对不起,我迟到了。

让我尝试使用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仅在数据模块中被列为依赖项(甚至不在父模块中)

在Eclipse中,dependencyManagement中还有一个特性。当使用依赖项而不使用它时,将在pom文件中注意到未找到的依赖项。如果使用dependencyManagement,则pom文件中不会发现未解决的依赖项,错误只出现在java文件中。(进口等…)

我不建议使用dependencyManagement。

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

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