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?为什么不直接在所需的模块中定义它?
答案 0 :(得分:577)
我对这个问题的时间已经很晚了,但我认为它比接受的答案更明确(这是正确的,但并不强调你需要的实际重要部分)推断自己)。
在父POM中, <dependencies>
与 <dependencyManagement>
之间的主要区别在于:
<dependencies>
部分中指定的工件将始终作为子模块的依赖项包含在内。
<dependencyManagement>
部分中指定的工件只会在子模块中包含,如果它们也在 <dependencies>
部分中指定子模块本身。你问为什么这么好?因为您在父项中指定了版本和/或作用域,并且在指定子POM中的依赖项时可以将它们保留。这可以帮助您为子模块使用统一版本的依赖项,而无需在每个子模块中指定版本。
答案 1 :(得分:388)
Dependency Management允许合并和集中管理依赖项版本,而无需添加所有子项继承的依赖项。当您拥有一组项目(即多个项目)继承公共父项时,此功能尤其有用。
dependencyManagement
的另一个非常重要的用例是控制传递依赖项中使用的工件版本。没有一个例子,这很难解释。幸运的是,这在文档中有说明。
答案 2 :(得分:44)
Maven网站上的documentation非常糟糕。 dependencyManagement所做的只是将您的依赖关系定义(版本,排除等)移动到父pom,然后在子poms中您只需要放置groupId和artifactId。这就是它(除了父pom链等之外,但这也不是很复杂 - dependencyManagement胜过父级别的依赖 - 但如果有关于那个或导入的问题,那么Maven文档好一点)。
阅读了所有的&#39;&#39;&#39;&#39; c&#39; Maven网站上的垃圾变得混乱,我重新写了他们的例子。因此,如果你有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>
答案 3 :(得分:43)
就像你说的那样; dependencyManagement
用于将所有依赖关系信息提取到公共POM文件中,从而简化子POM文件中的引用。
当您有多个属性不想在多个子项目中重新输入时,它会变得很有用。
最后,dependencyManagement
可用于定义要在多个项目中使用的工件的标准版本。
答案 4 :(得分:27)
在我看来,还有一件事情还不够突出,那就是不需要的继承。
这是一个增量示例:
我在我的parent
pom:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
</dependencies>
热潮!我在我的Child A
,Child B
和Child C
模块中使用了它:
version 18.0
中重新展示并覆盖Child B
。但是如果我最终不需要Child C
中的guava,以及将来Child D
和Child E
模块中的guava怎么办?
他们仍会继承它,这是不受欢迎的! 这就像Java God Object代码的气味,你从类中继承了一些有用的东西,还有一些不需要的东西。
这是<dependencyManagement>
发挥作用的地方。当您将其添加到父pom时,所有子模块停止查看。因此,您强制进入需要它的每个单独模块并再次声明它(Child A
和Child B
,但没有版本)。
显然,你不会为Child C
做这件事,因此你的模块仍然是精益的。
答案 5 :(得分:11)
有一些答案概述了<depedencies>
和<dependencyManagement>
标记与maven之间的差异。
然而,下面简要阐述了几点:
<dependencyManagement>
允许合并在不同模块中使用的所有依赖项(在子pom级别使用) - 清晰度,中央依赖项版本管理 <dependencyManagement>
允许根据需要轻松升级/降级依赖关系,在其他情况下,这需要在每个子pom级别执行 - 一致性 <dependencies>
标记中提供的依赖项,而仅当子pom在其<dependencyManagement>
标记中包含相应条目时,才会导入父pom中<dependencies>
处提供的依赖项。答案 6 :(得分:9)
如果依赖项是在顶级pom的dependencyManagement元素中定义的,则子项目不必显式列出依赖项的版本。如果子项目确实定义了一个版本,它将覆盖顶级列出的版本 POM的依赖管理部分。也就是说,dependencyManagement版本只是 当孩子没有直接申报版本时使用。
答案 7 :(得分:4)
在父POM中,<dependencies>
和<dependencyManagement>
之间的主要区别在于:
<dependencies>
部分中指定的工件将始终作为子模块的依赖项包含在内。
如果在子模块本身的部分中也指定了子模块,则该部分中指定的工件将仅包含在子模块中。你问为什么这么好?因为您在父项中指定了版本和/或作用域,并且在指定子POM中的依赖项时可以将它们保留。这可以帮助您为子模块使用统一版本的依赖项,而无需在每个子模块中指定版本。
答案 8 :(得分:4)
对不起,我参加聚会很晚。
让我尝试使用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番石榴被列为每个模块(包括父模块)中的依赖项,而 apache commons 仅被列为数据模块中的依赖项(甚至不在父模块中)
答案 9 :(得分:2)
用我自己的话说,parent-project
可以帮助您提供两种依赖关系:
<dependencies>
的{{1}} parent-project
中child-projects
部分中定义的所有依赖项
child-projects
中应用的依赖项。因此,您使用<dependencyManagement>
部分来声明要在不同child-projects
中使用的所有依赖项。最重要的是,在本节中,您将定义一个<version>
,这样您就不必在child-project
中再次声明它。 根据我的观点,<dependencyManagement>
(如果我错了,请纠正我)仅对帮助您集中依赖项的版本很有用。就像一种辅助功能。
答案 10 :(得分:1)
在Eclipse中,dependencyManagement
还有一个功能。如果在没有它的情况下使用dependencies
,则会在pom文件中注意到未发现的依赖项。如果使用dependencyManagement
,则未解决的依赖关系在pom文件中仍未被注意,并且错误仅出现在java文件中。 (进口等......)
答案 11 :(得分:1)
两者之间的区别最好体现在Maven网站文档中提供的dependencyManagement元素似乎是必需的和充分的定义:
dependencyManagement
“继承自此项目的项目的默认依赖关系信息。本节中的依赖关系不会立即得到解决。相反,当从此项目派生的POM声明由匹配的groupId和artifactId描述的依赖项时,版本和其他值如果尚未指定,则将使用此部分中的依赖项。” [https://maven.apache.org/ref/3.6.1/maven-model/maven.html]
应将其与其他页面上的更多信息一起阅读:
” ..用于将依赖项引用与dependencyManagement部分进行匹配的最小信息集实际上是{groupId,artifactId,type,classifier}。在许多情况下,这些依赖项将引用没有分类器的jar工件。由于类型字段的默认值为jar,默认分类器为null,因此这使我们可以简化设置为{groupId,artifactId}的标识。” [https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html]
因此,依赖项的所有子元素(作用域,排除项等)(除了groupId,artifactId,类型,分类器,不仅是版本)都可以在该点进行锁定/默认设置(和因此继承自此),您可以在dependencyElement中指定依赖项。如果您使用type和classifier子元素(请参见第一个引用的网页检查所有子元素)指定的依赖关系分别不是jar和not null,则需要{groupId,artifactId,classifier,type}引用(解析)该依赖关系,该依赖关系在依赖项中的任何时候都源自dependencyManagement元素。另外,如果您不打算覆盖分类器和类型的默认值(分别为jar和null),则{groupId,artifactId}就足够了。因此,default是该定义中的一个好关键字。在您引用依赖项时,任何明确指定值的子元素(当然,除了groupId,artifactId,分类器和类型之外)都将覆盖dependencyManagement元素中的默认值。
因此,无论是作为dependencyManagement元素的引用还是作为独立项的引用,dependencyManagement之外的任何依赖项元素都将立即得到解决(即,安装到本地存储库中并且可用于类路径)。
答案 12 :(得分:0)
如果您还是有一个pom,那么我认为仅使用<dependencyManagement>
来控制版本(可能是作用域)就是浪费空间,并使初级开发人员感到困惑。
无论如何,您都可能会在某种形式的parent-pom文件中具有版本的属性。为什么不只在子pom中使用此属性?这样,您仍然可以一次为所有子项目更新属性中的版本(在parent-pom中)。只是没有<dependencyManagement>
,其效果与<dependencyManagement>
相同。
我认为<dependencyManagement>
应该用于对依赖项的“真实”管理,例如排除等。
答案 13 :(得分:0)
<dependencyManagement>
的一个用例是解决库版本冲突。
示例:
有了这个集合,您将在项目 A 同时 x:1.0.1
和 x:1.0.0
的情况下发生冲突。
要解决此问题,您可以将特定版本的依赖项放入 <dependencyManagement>
标记