dependencyManagement 和 Maven 中的依赖关系之间的区别
-
26-09-2019 - |
题
有什么区别 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?为什么不直接在需要的模块中定义它呢?
解决方案
依赖管理允许巩固和集中依赖版本的管理不增加其被所有孩子继承的依赖关系。当你有这是特别有用的一组项目强>(即超过一个)继承一个共同的父。
dependencyManagement
的另一个非常重要的使用情况是在传递依赖使用的工件的版本的控制。这很难不一个例子来解释。幸运的是,此文档中被示出。
其他提示
我是时髦地迟到了这个问题,但我认为它的价值比接受一个更清晰的反应(这是正确的,但不强调实际的重要组成部分,你需要自己的推断)。
在父POM,在 <dependencies>
和<强> <dependencyManagement>
强>是本之间的主要区别是:
在 <dependencies>
部分将总是被包括作为子模块(一个或多个)的依赖性指定工件。
在 <dependencyManagement>
部分指定工件,将只被包括在子模块中,如果他们在 <dependencies>
强>子模块本身的部分也指定。为什么它好你问?因为您指定父版本和/或范围,并在孩子POM指定的依赖时,你可以离开他们。这可以帮助您使用统一版本的依赖关系子模块,无需每个孩子模块中指定版本。
上Maven站点的文档是可怕的。什么dependencyManagement确实是简单了移动你的依赖定义(版本,排除等),以父POM,然后在孩子劲歌你就必须把groupId和artifactId的。这就是它(除了父POM链接之类的,但是这不是很复杂或者 - dependencyManagement在母公司层面上的依赖胜出 - 但如果有这样或进口的问题,Maven的文件是一个好一点)。
读取所有的“a”,“B”,“C”的垃圾上Maven站点和感到困惑后,我重新写了例子。所以,如果你有2个项目(proj1和proj2),它都有一个共同的依赖(betaShared),你可以移动这种依赖到父POM。当你在这,你也可以移动的任何其他依赖(α和查理),但只有当它是有道理的项目。因此,对于在现有的句子中列出的情况下,这里是在父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>
这就像你说的; dependencyManagement
is用来拉所有的依赖性信息到一个共同的POM文件,简化了孩子POM文件的引用。
当你有多个属性,你不想重新输入下多个子项目变得非常有用。
最后,dependencyManagement
可用于定义一个标准的版本的伪影,以在多个项目中使用。
在我看来,还有一件事还不够突出,那就是 不需要的继承.
这是一个增量示例:
我在我的声明中声明 parent
pom:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
繁荣!我有它在我的 Child A
, Child B
和 Child C
模块:
- 子 poms 隐式继承
- 单一地点进行管理
- 无需在子 poms 中重新声明任何内容
- 我仍然可以重新定义并覆盖
version 18.0
在一个Child B
如果我想。
但如果我最终不需要番石榴怎么办 Child C
, ,并且将来也不会 Child D
和 Child E
模块?
他们仍然会继承它,这是不希望的!这就像 Java God Object 代码味道一样,您从类继承了一些有用的位,以及大量不需要的东西。
这是哪里 <dependencyManagement>
发挥作用。当您将其添加到父 pom 时,所有子模块 别再看到它了. 。因此你是 被迫 进入每个需要它的单独模块并再次声明它(Child A
和 Child B
, ,但没有版本)。
而且,显然,你这样做不是为了 Child C
, ,因此您的模块保持精简。
有几个答案概述了之间的差异 <depedencies>
和 <dependencyManagement>
带有 Maven 的标签。
然而,下面简要阐述了几点:
<dependencyManagement>
允许整合跨不同模块使用的所有依赖项(在子 pom 级别使用)—— 明晰, 中央依赖版本管理<dependencyManagement>
允许根据需要轻松升级/降级依赖项,在其他情况下,这需要在每个子 pom 级别上执行 - 一致性- 中提供的依赖项
<dependencies>
标签始终被导入,而依赖项提供于<dependencyManagement>
仅当子 pom 中具有相应条目时,才会导入父 pom 中的内容<dependencies>
标签。
如果依赖是在顶层POM的dependencyManagement元素定义,孩子的项目没有明确列出依赖的版本。如果孩子做项目定义一个版本,它会覆盖在顶层列出的版本 POM的dependencyManagement部分。也就是说,dependencyManagement版本只是 使用时,子不直接声明一个版本。
对不起我非常迟到了。
让我尝试使用解释差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
<强>谷歌番石榴强>被列为依赖每个模块(包括亲本)中,而在阿帕奇公地强>仅在数据模块被列为依赖性(未连在父模块)
在父POM,所述<dependencies>
和<dependencyManagement>
之间的主要区别是这样的:
在<dependencies>
部分指定工件将总是被包括作为子模块(一个或多个)的依赖关系。
在部分中指定工件,将只被包括在子模块中,如果他们在子模块本身的部分也指定。为什么它好你问?因为您指定父版本和/或范围,并在孩子POM指定的依赖时,你可以离开他们。这可以帮助您使用统一版本的依赖关系子模块,无需每个孩子模块中指定版本。
在Eclipse中,有在一个dependencyManagement
多个特征。当dependencies
时也没有用,unfound依赖性注意到了POM文件。如果使用dependencyManagement
,未解决的依赖关系仍然保留在POM文件被忽视,只有在java文件出现错误。 (进口和等...)
两者之间的区别最好引入 Maven 网站文档中提供的 dependencyManagement 元素的必要且充分的定义:
依赖管理
“从该项目继承的项目的默认依赖关系信息。本节中的依赖关系不会立即解决。相反,当从此派生的 POM 声明由匹配的 groupId 和 artifactId 描述的依赖项时,如果尚未指定此部分中的版本和其他值,则它们将用于该依赖项。 [ https://maven.apache.org/ref/3.6.1/maven-model/maven.html ]
应将其与其他页面上提供的更多信息一起阅读:
“..用于将依赖项引用与 dependencyManagement 部分进行匹配的最小信息集实际上是 {groupId、artifactId、type、classifier}。在许多情况下,这些依赖项将引用没有分类器的 jar 工件。这允许我们将标识集简写为 {groupId, artifactId},因为 type 字段的默认值是 jar,而默认分类器是 null。[https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html ]
因此,依赖元素的所有子元素(范围、排除等)——除了 groupId、artifactId、type、classifier,而不仅仅是版本——都可用于此时的锁定/默认(因此继承自在此之后)您可以在 dependencyElement 中指定依赖关系。如果您将 type 和 classifier 子元素(请参阅第一个引用的网页以检查所有子元素)分别指定为 not jar 和 not null 的依赖项,则需要 {groupId, artifactId, classifier, type}在源自 dependencyManagement 元素的继承中的任何点引用(解析)该依赖关系。否则,如果您不打算覆盖分类器和类型(分别为 jar 和 null)的默认值,则 {groupId, artifactId} 就足够了。所以 default 是该定义中的一个很好的关键字;任何子元素(当然,除了 groupId、artifactId、classifier 和 type 之外)在引用依赖项时显式分配的值都会覆盖 dependencyManagement 元素中的默认值。
因此,dependencyManagement 之外的任何依赖元素,无论是作为对某些 dependencyManagement 元素的引用还是作为独立元素,都会立即解析(即安装到本地存储库并可用于类路径)。