POM 参考
介绍
什么是 POM?
POM 代表“项目对象模型”。它是一个 Maven 项目的 XML 表示,保存在一个名为pom.xml
. 当在 Maven 的人面前,谈论一个项目是在哲学意义上的,而不仅仅是包含代码的文件集合。一个项目包含配置文件,以及涉及的开发人员和他们扮演的角色、缺陷跟踪系统、组织和许可证、项目所在的 URL、项目的依赖项以及所有其他小部分玩给代码生命。它是与项目有关的所有事情的一站式商店。事实上,在 Maven 世界中,一个项目根本不需要包含任何代码,只需一个pom.xml
.
快速概览
这是直接在 POM 的项目元素下的元素列表。注意modelVersion
包含 4.0.0。这是当前唯一受支持的 POM 版本,并且始终是必需的。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- The Basics --> <groupId>...</groupId> <artifactId>...</artifactId> <version>...</version> <packaging>...</packaging> <dependencies>...</dependencies> <parent>...</parent> <dependencyManagement>...</dependencyManagement> <modules>...</modules> <properties>...</properties> <!-- Build Settings --> <build>...</build> <reporting>...</reporting> <!-- More Project Information --> <name>...</name> <description>...</description> <url>...</url> <inceptionYear>...</inceptionYear> <licenses>...</licenses> <organization>...</organization> <developers>...</developers> <contributors>...</contributors> <!-- Environment Settings --> <issueManagement>...</issueManagement> <ciManagement>...</ciManagement> <mailingLists>...</mailingLists> <scm>...</scm> <prerequisites>...</prerequisites> <repositories>...</repositories> <pluginRepositories>...</pluginRepositories> <distributionManagement>...</distributionManagement> <profiles>...</profiles> </project>
基础
POM 包含有关项目的所有必要信息,以及要在构建过程中使用的插件配置。它是“who”、“what”和“where”的声明性表现,而构建生命周期是“when”和“how”。这并不是说 POM 不能影响生命周期的流程——它可以。例如,通过配置maven-antrun-plugin
,可以将 Apache Ant 任务嵌入到 POM 中。然而,这最终是一个宣言。虽然 abuild.xml
准确地告诉 Ant 在运行时要做什么(过程),但 POM 声明其配置(声明性)。如果某些外力导致生命周期跳过 Ant 插件的执行,它不会阻止执行的插件发挥它们的魔力。这不像一个build.xml
文件,其中任务几乎总是依赖于它之前执行的行。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.codehaus.mojo</groupId> <artifactId>my-project</artifactId> <version>1.0</version> </project>
Maven 坐标
上面定义的 POM 是 Maven 允许的最低限度。groupId:artifactId:version
都是必需的字段(尽管如果 groupId 和 version 是从父级继承的,则不需要显式定义 - 稍后将详细介绍继承)。这三个字段的作用很像一个地址和时间戳。这标记了存储库中的特定位置,就像 Maven 项目的坐标系:
- groupId:这在组织或项目中通常是唯一的。例如,所有核心 Maven 工件确实(应该)存在于 groupId 下
org.apache.maven
。组 ID 不一定使用点表示法,例如 junit 项目。请注意,以点表示的 groupId 不必与项目包含的包结构相对应。然而,这是一个很好的做法。当存储在存储库中时,该组的行为与 Java 打包结构在操作系统中的行为非常相似。这些点被操作系统特定的目录分隔符(例如 Unix 中的“/”)替换,这成为来自基本存储库的相对目录结构。在给出的示例中,该org.codehaus.mojo
组位于目录$M2_REPO/org/codehaus/mojo
中。 - artifactId:artifactId 通常是项目的名称。虽然 groupId 很重要,但组内的人很少会在讨论中提及 groupId(它们通常都是同一个 ID,例如MojoHaus项目的 groupId:
org.codehaus.mojo
)。它与 groupId 一起创建了一个将该项目与世界上所有其他项目分开的密钥(至少,它应该 :))。与 groupId 一起,artifactId 完全定义了工件在存储库中的生活区。在上述项目的情况下,my-project
居住在$M2_REPO/org/codehaus/mojo/my-project
. - version:这是命名难题的最后一块。
groupId:artifactId
表示单个项目,但他们无法描述我们正在谈论的该项目的哪个化身。我们想要junit:junit
2018 年(4.12 版)还是 2007 年(3.8.2 版)?简而言之:代码更改,这些更改应该进行版本控制,并且此元素使这些版本保持一致。它还用于工件的存储库中以将版本彼此分开。my-project
1.0 版文件位于目录结构$M2_REPO/org/codehaus/mojo/my-project/1.0
中。
上面给出的三个元素指向项目的特定版本,让 Maven 知道我们在处理谁,以及我们在其软件生命周期中何时需要它们。
包装
现在我们有了我们的地址结构groupId:artifactId:version
,还有一个标准标签来给我们一个真正完整的东西:那就是项目的包装。在我们的例子中,上面定义的示例 POMorg.codehaus.mojo:my-project:1.0
将被打包为jar
. war
我们可以通过声明一个不同的包装使它成为一个:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <packaging>war</packaging> ... </project>
当没有声明包装时,Maven 假定包装是默认的:jar
. 有效的类型是组件角色的 Plexus 角色提示(阅读更多关于 Plexus 以了解角色和角色提示的解释)org.apache.maven.lifecycle.mapping.LifecycleMapping
。当前的核心包装值是:pom
, jar
, maven-plugin
, ejb
, war
, ear
, rar
. 这些定义了在特定包结构的每个相应构建生命周期阶段执行的目标的默认列表:有关详细信息,请参阅默认生命周期参考的插件绑定。
POM 关系
Maven 的一个强大方面是它对项目关系的处理:这包括依赖关系(和传递依赖关系)、继承和聚合(多模块项目)。
依赖管理有着悠久的传统,即除了最琐碎的项目之外,任何事情都是一团糟。随着依赖关系树变得庞大而复杂,“Jarmageddon”很快就接踵而至。接下来是“Jar Hell”,其中一个系统上的依赖项版本与开发的版本不等价,要么是给出了错误的版本,要么是名称相似的 jar 之间的版本冲突。
Maven 通过一个公共的本地存储库解决了这两个问题,从该存储库中可以正确链接项目、版本和所有内容。
依赖项
POM 的基石是它的依赖列表。大多数项目都依赖于其他项目来正确构建和运行。如果 Maven 为您做的只是管理这个列表,那么您已经获得了很多。Maven 下载并链接编译的依赖关系,以及需要它们的其他目标。作为额外的好处,Maven 引入了这些依赖项的依赖项(传递依赖项),允许您的列表仅关注项目所需的依赖项。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <type>jar</type> <scope>test</scope> <optional>true</optional> </dependency> ... </dependencies> ... </project>
- groupId、artifactId、version:
您会经常看到这些元素。这三位一体用于及时计算特定项目的 Maven 坐标,将其划分为该项目的依赖项。这个计算的目的是选择一个匹配所有依赖声明的版本(由于传递依赖,同一个工件可以有多个依赖声明)。这些值应该是:- groupId , artifactId:直接对应依赖的坐标,
- version:依赖版本需求规范,用于计算依赖的有效版本。
由于依赖是通过 Maven 坐标来描述的,你可能会想:“这意味着我的项目只能依赖 Maven 工件!” 答案是,“当然,但这是件好事。” 这迫使您完全依赖 Maven 可以管理的依赖项。
不幸的是,有时无法从中央 Maven 存储库下载项目。例如,一个项目可能依赖于一个具有封闭源代码许可证的 jar,该许可证阻止它位于中央存储库中。有三种方法可以处理这种情况。
- 使用安装插件在本地安装依赖项。该方法是最简单的推荐方法。例如:
mvn install:install-file -Dfile=non-maven-proj.jar -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1 -Dpackaging=jar
请注意,仍然需要地址,只是这次您使用命令行,安装插件将为您创建一个具有给定地址的 POM。
- 创建您自己的存储库并将其部署到那里。对于拥有 Intranet 并且需要能够让每个人保持同步的公司来说,这是一种最喜欢的方法。有一个名为 Maven 的目标
deploy:deploy-file
,它类似于install:install-file
目标(阅读插件的目标页面以获取更多信息)。 - 将依赖范围设置为
system
并定义一个systemPath
. 但是,不建议这样做,但会引导我们解释以下元素:
- 分类器:
分类器区分从相同 POM 构建但内容不同的工件。它是一些可选且任意的字符串——如果存在的话——被附加到工件名称之后,紧跟在版本号之后。作为这个元素的动机,例如考虑一个项目,它提供了一个面向 Java 11 的工件,但同时也提供了一个仍然支持 Java 1.8 的工件。第一个工件可以配备分类器
jdk11
,第二个工件可以配备分类器,jdk8
以便客户可以选择使用哪一个。分类器的另一个常见用例是将辅助工件附加到项目的主要工件。如果您浏览 Maven 中央存储库,您会注意到分类器
sources
和javadoc
用于部署项目源代码和 API 文档以及打包的类文件。 - type:
对应于选择的依赖类型。这默认为jar
. 虽然它通常表示依赖项文件名的扩展名,但情况并非总是如此:一个类型可以映射到不同的扩展名和分类器。类型通常与使用的包装相对应,但也并非总是如此。一些示例是jar
,ejb-client
和test-jar
: 请参阅列表的默认工件处理程序。新类型可以由设置extensions
为 true 的插件定义,所以这不是一个完整的列表。 - scope:
该元素指的是手头任务的类路径(编译和运行时、测试等)以及如何限制依赖项的传递性。有五个可用范围:- compile - 这是默认范围,如果没有指定,则使用。编译依赖项在所有类路径中都可用。此外,这些依赖关系会传播到依赖项目。
- 提供- 这很像编译,但表示您希望 JDK 或容器在运行时提供它。它仅在编译和测试类路径中可用,并且不可传递。
- 运行时- 此范围表示编译不需要依赖项,但需要执行。它在运行时和测试类路径中,但不在编译类路径中。
- test - 此范围表示应用程序的正常使用不需要依赖项,仅可用于测试编译和执行阶段。它不是传递的。
- system - 这个范围类似于
provided
除了你必须提供明确包含它的 JAR 之外。工件始终可用,不会在存储库中查找。
- systemPath :
仅在依赖项为时使用。否则,如果设置了此元素,则构建将失败。路径必须是绝对的,因此建议使用属性来指定机器特定的路径(更多内容见下文),例如. 由于假定系统范围依赖项是先验安装的,因此 Maven 不会检查项目的存储库,而是检查以确保文件存在。如果没有,Maven 会导致构建失败,并建议您手动下载并安装它。scope
system
properties
${java.home}/lib
- optional:
当此项目本身是依赖项时,将依赖项标记为可选。例如,假设一个项目A
依赖于项目B
来编译运行时可能不会使用的部分代码,那么我们可能不需要B
所有项目的项目。因此,如果项目X
添加项目A
作为自己的依赖项,那么 Maven 根本不需要安装项目B
。象征性地, if=>
表示必需的依赖项,并-->
表示可选的,尽管A=>B
在构建 A 时可能是这种情况,而在构建时X=>A-->B
可能是这种情况X
。简而言之,
optional
让其他项目知道,当您使用此项目时,您不需要此依赖项即可正常工作。
依赖版本需求规范
依赖项的version
元素定义版本要求,用于计算依赖项版本。软需求可以被依赖图中其他地方找到的相同工件的不同版本替换。硬性要求要求一个或多个特定版本,并覆盖软性要求。如果没有满足该工件的所有硬性要求的依赖项版本,则构建失败。
版本要求具有以下语法:
1.0
: 1.0 的软要求。如果依赖关系树中没有其他版本出现,请使用 1.0。[1.0]
: 对 1.0 的硬性要求。使用 1.0 且仅使用 1.0。(,1.0]
:任何版本 <= 1.0 的硬性要求。[1.2,1.3]
: 对 1.2 和 1.3 之间的任何版本的硬性要求。[1.0,2.0)
: 1.0 <= x < 2.0; 对 1.0 包容性和 2.0 独有性之间的任何版本的硬性要求。[1.5,)
:对任何大于或等于 1.5 的版本的硬性要求。(,1.0],[1.2,)
: 对任何小于或等于 1.0 大于或大于或等于 1.2 的版本的硬性要求,但不是 1.1。多个需求用逗号分隔。(,1.1),(1.1,)
: 对除 1.1 以外的任何版本的硬性要求;例如因为 1.1 有一个严重的漏洞。Maven 选择每个项目的最高版本,以满足该项目依赖项的所有硬性要求。如果没有版本满足所有硬性要求,则构建失败。
版本订购规范:
如果版本字符串在语法上是正确的Semantic Versioning 1.0.0版本号,那么在几乎所有情况下,版本比较都遵循该规范中概述的优先规则。这些版本是常见的字母数字 ASCII 字符串,例如 2.15.2-alpha。更准确地说,如果要比较的两个版本号都与语义版本控制规范中的 BNF 语法中的“有效 semver”产生式相匹配,则这是正确的。Maven 不考虑该规范隐含的任何语义。
重要提示:这仅适用于 Semantic Versioning 1.0.0。Maven 版本顺序算法与 Semantic Versioning 2.0.0不兼容。特别是,Maven 不会对加号进行特殊处理或考虑构建标识符。
当版本字符串不遵循语义版本控制时,需要一组更复杂的规则。Maven 坐标分为点 (' .
')、连字符 (' -
') 之间的标记以及数字和字符之间的转换。分隔符被记录下来,将对订单产生影响。数字和字符之间的转换相当于一个连字符。空标记替换为“ 0
”。.
这给出了带有“ ”或“ -
”前缀的版本号(数字标记)和版本限定符(非数字标记)序列。
拆分和替换示例:
1-1.foo-bar1baz-.1
->1-1.foo-bar-1-baz-0.1
然后,从版本末尾开始,修剪尾随的“空”值( 0
、""
、“ final
”、“ ”)。ga
在每个剩余的连字符处从头到尾重复此过程。
修剪示例:
1.0.0
->1
1.ga
->1
1.final
->1
1.0
->1
1.
->1
1-
->1
1.0.0-foo.0.0
->1-foo
1.0.0-0.0.0
->1
版本顺序是lexicographical order
在这个前缀标记序列上,较短的一个用足够的“空”值填充,具有匹配的前缀以具有与较长的相同的长度。填充的“null”值取决于其他版本的前缀:0 表示“.”,“”表示“-”。前缀令牌顺序为:
- 如果前缀相同,则比较令牌:
- 数字标记具有自然顺序。
- 非数字标记(“限定符”)按字母顺序排列,但以下标记按此顺序排在首位:
"
alpha
" < "beta
" < "milestone
" < "rc
" = "cr
" < "snapshot
" < "" = "final
" = "ga
" < "sp
"- "
alpha
"、"beta
" 和 "milestone
" 限定词在直接跟数字时可以分别缩短为 "a"、"b" 和 "m"。
- "
- 否则"
.qualifier
"<"-qualifier
"<"-number
"<".number
"
最终结果示例:
- "
1
" < "1.1
" (数字填充) - "
1-snapshot
" < "1
" < "1-sp
" (限定符填充) - "
1-foo2
" < "1-foo10
" (正确地自动“切换”到数字顺序) - "
1.foo
" < "1-foo
" < "1-1
" < "1.1
" - "
1.ga
" = "1-ga
" = "1-0
" = "1.0
" = "1
" (删除尾随的“空”值) - "
1-sp
" > "1-ga
" - "
1-sp.1
" > "1-ga.1
" - "
1-sp-1
" < "1-ga-1
" = "1-1
" (每个连字符的尾随“空”值) - “
1-a1
”=“1-alpha-1
”注意:与某些设计文档中所述相反,对于版本顺序,快照的处理方式与版本或任何其他限定符没有区别。
注意:由于
2.0-rc1
<2.0
,版本要求[1.0,2.0)
排除2.0
但包含 version2.0-rc1
,这与大多数人的期望相反。此外,Gradle 对它的解释不同,导致同一个 POM 的依赖树不同。如果打算将其限制为1.*版本,则更好的版本要求是[1,1.999999)
.
版本顺序测试:
maven 发行版包括一个检查版本顺序的工具。它用于生成前面段落中的示例。如有疑问,请随时自行运行。你可以像这样运行它:
java -jar ${MAVEN_HOME}/lib/maven-artifact-3.3.9.jar [versions...]
例子:
$ java -jar ./lib/maven-artifact-3.3.9.jar 1 2 1.1 Display parameters as parsed by Maven (in canonical form) and comparison result: 1. 1 == 1 1 < 2 2. 2 == 2 2 > 1.1 3. 1.1 == 1.1
排除项
排除项告诉 Maven 不包含作为此依赖项的依赖项的指定项目(换句话说,它的传递依赖项)。例如,maven-embedder
requires maven-core
,并且我们不希望使用它或其依赖项,那么我们会将其添加为exclusion
.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <dependencies> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-embedder</artifactId> <version>2.0</version> <exclusions> <exclusion> <groupId>org.apache.maven</groupId> <artifactId>maven-core</artifactId> </exclusion> </exclusions> </dependency> ... </dependencies> ... </project>
剪裁依赖项的传递依赖项有时也很有用。依赖项可能有错误指定的范围,或者与项目中其他依赖项冲突的依赖项。使用通配符排除可以轻松排除所有依赖项的传递依赖项。在下面的情况下,您可能正在使用 maven-embedder,并且您想管理自己使用的依赖项,因此您剪辑了所有传递依赖项:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <dependencies> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-embedder</artifactId> <version>3.1.0</version> <exclusions> <exclusion> <groupId>*</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> ... </dependencies> ... </project>
- excludes :排除包含一个或多个
exclusion
元素,每个元素都包含一个groupId
并artifactId
表示要排除的依赖项。不像optional
,可能会或可能不会安装和使用,exclusions
主动从依赖关系树中删除自己。
遗产
Maven 为构建管理带来的一项强大功能是项目继承的概念。尽管可以模拟 Ant 继承等构建系统,但 Maven 使项目继承在项目对象模型中显式化。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.codehaus.mojo</groupId> <artifactId>my-parent</artifactId> <version>2.0</version> <packaging>pom</packaging> </project>
父项目和聚合(多模块)项目packaging
所需的类型pom
。这些类型定义了绑定到一组生命周期阶段的目标。例如,如果包装是,那么阶段将执行目标。现在我们可以向父 POM 添加值,该 POM 将由其子代继承。来自父 POM 的大多数元素都由其子代继承,包括:jar
package
jar:jar
- 组 ID
- 版本
- 描述
- 网址
- 成立年份
- 组织
- 许可证
- 开发商
- 贡献者
- 邮件列表
- 单片机
- 问题管理
- 企业管理
- 特性
- 依赖管理
- 依赖关系
- 存储库
- 插件存储库
- 建造
- 具有匹配 id 的插件执行
- 插件配置
- 等等。
- 报告
- 简介
not
继承的值得注意的元素包括:
- 工件 ID
- 姓名
- 先决条件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.codehaus.mojo</groupId> <artifactId>my-parent</artifactId> <version>2.0</version> <relativePath>../my-parent</relativePath> </parent> <artifactId>my-project</artifactId> </project>
注意relativePath
元素。它不是必需的,但可以用作 Maven 的指示符,在搜索本地存储库和远程存储库之前,首先搜索为该项目的父项指定的路径。
超级 POM
与面向对象编程中的对象继承类似,扩展父 POM 的 POM 从该父 POM 继承某些值。此外,正如 Java 对象最终继承自 一样java.lang.Object
,所有项目对象模型都继承自基础 Super POM。下面的代码片段是 Maven 3.5.4 的 Super POM。
<project> <modelVersion>4.0.0</modelVersion> <repositories> <repository> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> <releases> <updatePolicy>never</updatePolicy> </releases> </pluginRepository> </pluginRepositories> <build> <directory>${project.basedir}/target</directory> <outputDirectory>${project.build.directory}/classes</outputDirectory> <finalName>${project.artifactId}-${project.version}</finalName> <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory> <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory> <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory> <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory> <resources> <resource> <directory>${project.basedir}/src/main/resources</directory> </resource> </resources> <testResources> <testResource> <directory>${project.basedir}/src/test/resources</directory> </testResource> </testResources> <pluginManagement> <!-- NOTE: These plugins will be removed from future versions of the super POM --> <!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) --> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.3</version> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-5</version> </plugin> <plugin> <artifactId>maven-dependency-plugin</artifactId> <version>2.8</version> </plugin> <plugin> <artifactId>maven-release-plugin</artifactId> <version>2.5.3</version> </plugin> </plugins> </pluginManagement> </build> <reporting> <outputDirectory>${project.build.directory}/site</outputDirectory> </reporting> <profiles> <!-- NOTE: The release profile will be removed from future versions of the super POM --> <profile> <id>release-profile</id> <activation> <property> <name>performRelease</name> <value>true</value> </property> </activation> <build> <plugins> <plugin> <inherited>true</inherited> <artifactId>maven-source-plugin</artifactId> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> <plugin> <inherited>true</inherited> <artifactId>maven-javadoc-plugin</artifactId> <executions> <execution> <id>attach-javadocs</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <inherited>true</inherited> <artifactId>maven-deploy-plugin</artifactId> <configuration> <updateReleaseInfo>true</updateReleaseInfo> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>
您可以通过创建一个最小的pom.xml
并在命令行上执行来查看 Super POM 如何影响您的项目对象模型:mvn help:effective-pom
依赖管理
除了继承某些顶级元素外,父母还可以为子 POM 和传递依赖项配置值。这些元素之一是dependencyManagement
.
- dependencyManagement:POM 使用它来帮助管理其所有子项的依赖关系信息。如果
my-parent
项目用来dependencyManagement
定义对 的依赖junit:junit:4.12
,那么从这个继承的 POM 可以设置它们的依赖,只给出groupId
=junit
和artifactId
=junit
,Maven 将填充version
父级的集合。这种方法的好处是显而易见的。可以在一个中心位置设置依赖关系详细信息,该位置会传播到所有继承的 POM。请注意,从传递依赖项合并的工件的版本和范围也由依赖项管理部分中的版本规范控制。这可能会导致意想不到的后果。考虑一种情况,您的项目使用两个依赖项,
dep1
并且dep2
.dep2
反过来也使用dep1
, 并且需要特定的最低版本才能运行。如果再使用dependencyManagement
指定旧版本,dep2
将强制使用旧版本,并失败。所以,你必须小心检查整个依赖树以避免这个问题;mvn dependency:tree
很有帮助。
聚合(或多模块)
具有模块的项目称为多模块或聚合器项目。模块是这个 POM 列出的项目,并作为一个组执行。打包的pom
项目可以通过将一组项目列为模块来聚合它们的构建,模块是这些项目的目录或 POM 文件的相对路径。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.codehaus.mojo</groupId> <artifactId>my-parent</artifactId> <version>2.0</version> <packaging>pom</packaging> <modules> <module>my-project</module> <module>another-project</module> <module>third-project/pom-example.xml</module> </modules> </project>
列出模块时,您不需要自己考虑模块间的依赖关系;即 POM 给出的模块顺序并不重要。Maven 将对模块进行拓扑排序,使得依赖关系总是在依赖模块之前构建。
要查看聚合的实际效果,请查看Maven或Maven Core Plugins基础 POM。
关于继承与聚合的最后说明
继承和聚合创建了一个很好的动态来通过单个高级 POM 控制构建。您经常看到既是父项又是聚合者的项目。例如,整个 Maven 核心通过单个基础 POM 运行org.apache.maven:maven
,因此构建 Maven 项目可以通过单个命令执行:mvn compile
. 但是,聚合器项目和父项目都是 POM 项目,它们不是一回事,不应混淆。POM 项目可以继承自——但不一定具有——它聚合的任何模块。相反,POM 项目可能会聚合不继承自它的项目。
特性
属性是理解 POM 基础知识的最后一部分。Maven 属性是值占位符,类似于 Ant 中的属性。它们的值可以通过使用表示法在 POM 中的任何位置访问${X}
,属性在哪里X
。或者它们可以被插件用作默认值,例如:
<project> ... <properties> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> <!-- Following project.-properties are reserved for Maven in will become elements in a future POM definition. --> <!-- Don't start your own properties properties with project. --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> ... </project>
它们有五种不同的风格:
env.X
:用“env”为变量添加前缀。将返回 shell 的环境变量。例如,${env.PATH}
包含 PATH 环境变量。注意:虽然环境变量本身在 Windows 上不区分大小写,但查找属性时区分大小写。换句话说,虽然 Windows shell 为
%PATH%
and返回相同的值%Path%
,但 Maven 区分${env.PATH}
and${env.Path}
。为了可靠起见,环境变量的名称被规范化为全部大写。project.x
:POM 中的点 (.) 表示的路径将包含相应元素的值。例如:<project><version>1.0</version></project>
可通过${project.version}
.settings.x
: 中的点 (.) 表示的路径settings.xml
将包含相应元素的值。例如:<settings><offline>false</offline></settings>
可通过${settings.offline}
.- Java 系统属性:可通过
java.lang.System.getProperties()
POM 属性访问的所有属性,例如${java.home}
. x
:<properties />
在 POM 中的元素内设置。的值<properties><someVar>value</someVar></properties>
可以用作${someVar}
。
构建设置
除了上面给出的 POM 的基础知识之外,在声称 POM 的基本能力之前,还必须了解另外两个要素。它们是build
处理诸如声明项目的目录结构和管理插件等事情的元素;和reporting
元素,它在很大程度上反映了用于报告目的的构建元素。
建造
根据 POM 4.0.0 XSD,build
元素在概念上分为两部分:有一个BaseBuild
包含两个build
元素共有的元素集的类型(顶层构建元素project
和 下的构建元素profiles
,如下所述);还有一个Build
类型,它包含BaseBuild
集合以及顶级定义的更多元素。让我们从分析两者之间的共同点开始。
注意:这些不同的 build
元素可以表示为“项目构建”和“配置文件构建”。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <!-- "Project Build" contains more elements than just the BaseBuild set --> <build>...</build> <profiles> <profile> <!-- "Profile Build" contains a subset of "Project Build"s elements --> <build>...</build> </profile> </profiles> </project>
BaseBuild元素集
BaseBuild
就像听起来一样:build
POM 中两个元素之间的基本元素集。
<build> <defaultGoal>install</defaultGoal> <directory>${basedir}/target</directory> <finalName>${artifactId}-${version}</finalName> <filters> <filter>filters/filter1.properties</filter> </filters> ... </build>
- defaultGoal:如果没有给出默认的目标或阶段来执行。如果给出了一个目标,它应该在命令行中定义(例如
jar:jar
)。如果定义了阶段(例如安装),情况也是如此。 - directory:这是构建将转储其文件的目录,或者用 Maven 的说法,构建的目标。它恰当地默认为
${basedir}/target
. - finalName:这是最终构建时捆绑项目的名称(没有文件扩展名,例如:)
my-project-1.0.jar
。它默认为${artifactId}-${version}
. 然而,术语“finalName”有点用词不当,因为构建捆绑项目的插件完全有权忽略/修改此名称(但它们通常不会)。例如,如果maven-jar-plugin
被配置为给一个 jar aclassifier
,test
那么上面定义的实际 jar 将被构建为my-project-1.0-test.jar
. - filter:定义
*.properties
包含属性列表的文件,这些属性适用于接受其设置的资源(如下所述)。换句话说,name=value
过滤器文件中定义的“”对${name}
在构建时替换了资源中的字符串。上面的例子定义了filter1.properties
目录下的filters/
文件。Maven 的默认过滤器目录是${basedir}/src/main/filters/
.要更全面地了解过滤器是什么以及它们可以做什么,请查看快速入门指南。
资源
元素的另一个特性build
是指定项目中资源的位置。资源(通常)不是代码。它们不是编译的,而是要捆绑在您的项目中或用于各种其他原因(例如代码生成)的项目。
例如,Plexus 项目需要一个configuration.xml
文件(指定容器的组件配置)位于META-INF/plexus
目录中。虽然我们可以很容易地将这个文件src/main/resources/META-INF/plexus
放在src/main/plexus
. 为了让 JAR 插件正确捆绑资源,您将指定类似于以下内容的资源:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <build> ... <resources> <resource> <targetPath>META-INF/plexus</targetPath> <filtering>false</filtering> <directory>${basedir}/src/main/plexus</directory> <includes> <include>configuration.xml</include> </includes> <excludes> <exclude>**/*.properties</exclude> </excludes> </resource> </resources> <testResources> ... </testResources> ... </build> </project>
- resources:是资源元素的列表,每个元素都描述了包含与该项目相关的文件的内容和位置。
- targetPath:指定目录结构以放置来自构建的资源集。目标路径默认为基目录。将打包在 JAR 中的资源的常用指定目标路径是 META-INF。
- 过滤:是
true
或false
,表示是否要为此资源启用过滤。请注意,过滤*.properties
文件不必为过滤进行定义 - 资源也可以使用在 POM 中默认定义的属性(例如 ${project.version}),使用“-D”传递到命令行" 标志(例如, "-Dname
=value
")或由属性元素显式定义。上面介绍了过滤器文件。 - directory:此元素的值定义要在哪里找到资源。构建的默认目录是
${basedir}/src/main/resources
. - include:一组文件模式,指定要作为资源包含在该指定目录下的文件,使用 * 作为通配符。
- excludes:与 相同的结构
includes
,但指定要忽略的文件。include
在和之间的冲突中exclude
,exclude
获胜。 - testResources:
testResources
元素块包含testResource
元素。它们的定义类似于resource
元素,但在测试阶段自然使用。一个区别是项目的默认(超级 POM 定义)测试资源目录是${basedir}/src/test/resources
. 未部署测试资源。
插件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <build> ... <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.6</version> <extensions>false</extensions> <inherited>true</inherited> <configuration> <classifier>test</classifier> </configuration> <dependencies>...</dependencies> <executions>...</executions> </plugin> </plugins> </build> </project>
除了 的标准坐标之外groupId:artifactId:version
,还有一些元素可以配置插件或与它建立交互。
- extensions :
true
或false
, 是否加载此插件的扩展。默认为假。本文档稍后将介绍扩展。 - 继承:
true
或false
,此插件配置是否应应用于从该插件继承的 POM。默认值为true
。 - 配置:这是特定于单个插件的。无需深入了解插件如何工作的机制,只要说 Mojo 插件可能期望的任何属性(这些是 Java Mojo bean 中的 getter 和 setter)都可以在此处指定就足够了。在上面的示例中,我们将分类器属性设置为在
maven-jar-plugin
Mojo 中进行测试。值得注意的是,所有配置元素,无论它们在 POM 中的何处,都旨在将值传递给另一个底层系统,例如插件。换句话说:configuration
元素中的值从不被 POM 模式明确要求,但插件目标完全有权要求配置值。如果您的 POM 声明了父级,它会从父级的build/plugins或pluginManagement部分继承插件配置。
- 默认配置继承:
为了说明,请考虑来自父 POM 的以下片段:
<plugin> <groupId>my.group</groupId> <artifactId>my-plugin</artifactId> <configuration> <items> <item>parent-1</item> <item>parent-2</item> </items> <properties> <parentKey>parent</parentKey> </properties> </configuration> </plugin>
并考虑使用该父级作为其父级的项目中的以下插件配置:
<plugin> <groupId>my.group</groupId> <artifactId>my-plugin</artifactId> <configuration> <items> <item>child-1</item> </items> <properties> <childKey>child</childKey> </properties> </configuration> </plugin>
默认行为是根据元素名称合并配置元素的内容。如果子 POM 具有特定元素,则该值将成为有效值。如果子 POM 没有元素,但父 POM 有,则父值成为有效值。请注意,这纯粹是对 XML 的操作;不涉及插件本身的代码或配置。只涉及元素,而不是它们的值。
将这些规则应用于示例,Maven 提出:
<plugin> <groupId>my.group</groupId> <artifactId>my-plugin</artifactId> <configuration> <items> <item>child-1</item> </items> <properties> <childKey>child</childKey> <parentKey>parent</parentKey> </properties> </configuration> </plugin>
- 高级配置继承:
combine.children
和combine.self
您可以通过向配置元素的子元素添加属性来控制子 POM 如何从父 POM 继承配置。属性是
combine.children
和combine.self
。在子 POM 中使用这些属性来控制 Maven 如何将来自父级的插件配置与子级中的显式配置结合起来。这是带有两个属性插图的子配置:
<configuration> <items combine.children="append"> <!-- combine.children="merge" is the default --> <item>child-1</item> </items> <properties combine.self="override"> <!-- combine.self="merge" is the default --> <childKey>child</childKey> </properties> </configuration>
现在,有效的结果如下:
<configuration> <items combine.children="append"> <item>parent-1</item> <item>parent-2</item> <item>child-1</item> </items> <properties combine.self="override"> <childKey>child</childKey> </properties> </configuration>
combine.children="append"导致父元素和子元素按该顺序连接。另一方面,combine.self="override"完全抑制父配置。你不能在一个元素上同时使用combine.self="override"和combine.children="append" ;如果你尝试,覆盖将占上风。
请注意,这些属性仅适用于声明它们的配置元素,不会传播到嵌套元素。也就是说,如果来自子 POM 的item元素的内容是一个复杂的结构而不是文本,那么它的子元素仍将服从默认的合并策略,除非它们本身被标记了属性。
这些
combine.*
属性从父 POM 继承到子 POM。将这些属性添加到父 POM 时要小心,因为这可能会影响子 POM 或孙 POM。
- 默认配置继承:
- dependencies:在 POM 中可以看到很多依赖项,并且是所有插件元素块下的一个元素。依赖项具有与该基本构建相同的结构和功能。这种情况下的主要区别在于,它们现在不是作为项目的依赖项应用,而是作为它们所在插件的依赖项应用。这样做的威力是改变插件的依赖列表,可能是通过删除未使用的运行时依赖
exclusions
,或者通过改变所需依赖的版本。有关更多信息,请参见上文的依赖项。 - executions:重要的是要记住一个插件可能有多个目标。每个目标可能有一个单独的配置,甚至可能将插件的目标完全绑定到不同的阶段。
executions
配置execution
插件的目标。例如,假设您想将
antrun:run
目标绑定到verify
阶段。我们希望任务回显构建目录,并通过设置inherited
为false
. 你会得到execution
这样的:<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <build> <plugins> <plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.1</version> <executions> <execution> <id>echodir</id> <goals> <goal>run</goal> </goals> <phase>verify</phase> <inherited>false</inherited> <configuration> <tasks> <echo>Build Dir: ${project.build.directory}</echo> </tasks> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
- id:不言自明。它在所有其他执行块之间指定此执行块。当阶段运行时,它将以以下形式显示:。在此示例中:
[plugin:goal execution: id]
[antrun:run execution: echodir]
- 目标:像所有复数 POM 元素一样,它包含一个单数元素列表。在这种情况下,
goals
此execution
块指定的插件列表。 - phase:这是目标列表将执行的阶段。这是一个非常强大的选项,允许将任何目标绑定到构建生命周期中的任何阶段,从而改变 Maven 的默认行为。
- 继承:与
inherited
上面的元素一样,将其设置为 false 将禁止 Maven 将此执行传递给其子级。此元素仅对父 POM 有意义。 - configuration:与上面相同,但将配置限制在此特定目标列表中,而不是插件下的所有目标。
- id:不言自明。它在所有其他执行块之间指定此执行块。当阶段运行时,它将以以下形式显示:。在此示例中:
插件管理
- pluginManagement : 是一个可以在侧面插件中看到的元素。插件管理以几乎相同的方式包含插件元素,除了不是为这个特定的项目构建配置插件信息,它旨在配置从这个项目继承的项目构建。但是,这只配置了在子元素或当前 POM 中的 plugins 元素中实际引用的插件。孩子们有权推翻
pluginManagement
定义。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <build> ... <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.6</version> <executions> <execution> <id>pre-process-classes</id> <phase>compile</phase> <goals> <goal>jar</goal> </goals> <configuration> <classifier>pre-process</classifier> </configuration> </execution> </executions> </plugin> </plugins> </pluginManagement> ... </build> </project>
如果我们将这些规范添加到 plugins 元素中,它们将仅适用于单个 POM。但是,如果我们在pluginManagement
元素下应用它们,那么这个 POM和所有添加到构建中的继承 POM也将得到执行。因此,除了每个 child 中包含的上述混乱之外,只需要以下内容:maven-jar-plugin
pre-process-classes
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <build> ... <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> </plugin> </plugins> ... </build> </project>
构建元素集
XSD 中的Build
类型表示那些仅可用于“项目构建”的元素。尽管有很多额外的元素(六个),但实际上只有两组项目构建包含在配置文件构建中缺少的元素:目录和扩展。
目录
目录元素集存在于父构建元素中,它为整个 POM 设置各种目录结构。由于它们不存在于配置文件构建中,因此配置文件无法更改它们。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <build> <sourceDirectory>${basedir}/src/main/java</sourceDirectory> <scriptSourceDirectory>${basedir}/src/main/scripts</scriptSourceDirectory> <testSourceDirectory>${basedir}/src/test/java</testSourceDirectory> <outputDirectory>${basedir}/target/classes</outputDirectory> <testOutputDirectory>${basedir}/target/test-classes</testOutputDirectory> ... </build> </project>
如果上述*Directory
元素的值设置为绝对路径(当它们的属性展开时),则使用该目录。否则,它是相对于基本构建目录的:${basedir}
. 请注意 scriptSourceDirectory
Maven 中无处使用并且已过时。
扩展
扩展是要在此构建中使用的工件列表。它们将包含在正在运行的构建的类路径中。它们可以启用构建过程的扩展(例如为 Wagon 传输机制添加 ftp 提供程序),以及激活插件以更改构建生命周期。简而言之,扩展是在构建期间激活的工件。扩展不需要实际做任何事情,也不需要包含 Mojo。出于这个原因,扩展非常适合指定通用插件接口的多个实现中的一个。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <build> ... <extensions> <extension> <groupId>org.apache.maven.wagon</groupId> <artifactId>wagon-ftp</artifactId> <version>1.0-alpha-3</version> </extension> </extensions> ... </build> </project>
报告
报告包含专门对应于site
生成阶段的元素。某些 Maven 插件可以生成在报告元素下定义和配置的报告,例如:生成 Javadoc 报告。就像构建元素配置插件的能力一样,报告命令也具有相同的能力。明显的区别在于,报告不是在执行块内对插件目标进行细粒度控制,而是在reportSet
元素内配置目标。更微妙的区别是元素configuration
下的插件reporting
作为build
插件工作configuration
,尽管相反是不正确的(build
插件configuration
不影响reporting
插件)。
reporting
可能理解该元素的人不熟悉该元素下的唯一项目build
是布尔excludeDefaults
元素。此元素表示站点生成器排除默认情况下通常生成的报告。site
当通过构建周期生成站点时,左侧菜单中会放置一个项目信息部分,其中充满了报告,例如项目团队报告或依赖关系列表报告。这些报告目标由maven-project-info-reports-plugin
. 作为一个像任何其他插件一样的插件,它也可以通过以下更详细的方式被抑制,这有效地关闭了项目信息报告。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <reporting> <outputDirectory>${basedir}/target/site</outputDirectory> <plugins> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> <version>2.0.1</version> <reportSets> <reportSet></reportSet> </reportSets> </plugin> </plugins> </reporting> ... </project>
另一个区别是outputDirectory
下的元素plugin
。在报告的情况下,输出目录是${basedir}/target/site
默认的。
报告集
重要的是要记住,单个插件可能有多个目标。每个目标可能有一个单独的配置。报告集配置报告插件目标的执行。这听起来很熟悉 - 似曾相识吗?关于 build 的execution
元素也有相同的说法,但有一个区别:您不能将报告绑定到另一个阶段。对不起。
例如,假设您想将javadoc:javadoc
目标配置为链接到“ http://java.sun.com/j2se/1.5.0/docs/api/ ”,但只有javadoc
目标(不是目标maven-javadoc-plugin:jar
)。我们还希望将此配置传递给它的孩子,并设置inherited
为 true。将reportSet
类似于以下内容:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <reporting> <plugins> <plugin> ... <reportSets> <reportSet> <id>sunlink</id> <reports> <report>javadoc</report> </reports> <inherited>true</inherited> <configuration> <links> <link>http://java.sun.com/j2se/1.5.0/docs/api/</link> </links> </configuration> </reportSet> </reportSets> </plugin> </plugins> </reporting> ... </project>
在构建executions
和报告之间reportSets
,现在应该清楚它们为什么存在。从最简单的意义上说,它们深入配置。POM 不仅必须有一种方法来配置插件,而且还必须配置这些插件的目标。这就是这些元素的用武之地,为 POM 提供了控制其构建命运的最终粒度。
更多项目信息
几个元素不影响构建,而是为方便开发人员记录项目。其中许多元素用于在生成项目的网站时填写项目详细信息。然而,就像所有 POM 声明一样,插件可以将它们用于任何事情。以下是最简单的元素:
- name:项目往往具有会话名称,超出
artifactId
. Sun 工程师并没有将他们的项目称为“java-1.5”,而只是将其称为“Tiger”。这是设置该值的位置。 - description:项目的简短、人类可读的描述。尽管这不应取代正式文档,但对 POM 的任何读者的快速评论总是有帮助的。
- url:项目的主页。
- inceptionYear:项目首次创建的年份。
许可证
<licenses> <license> <name>Apache License, Version 2.0</name> <url>https://www.apache.org/licenses/LICENSE-2.0.txt</url> <distribution>repo</distribution> <comments>A business-friendly OSS license</comments> </license> </licenses>
许可证是定义如何以及何时使用项目(或项目的一部分)的法律文件。项目应列出直接适用于该项目的许可证,而不是列出适用于项目依赖项的许可证。
- name , url和comments : 是不言自明的,之前在其他上下文中遇到过。建议使用SPDX 标识符作为许可证名称。第四个许可证元素是:
- 分发:这描述了项目如何合法分发。这两种方法是 repo(它们可以从 Maven 存储库下载)或手动(它们必须手动安装)。
组织
大多数项目由某种组织(企业、私人团体等)运行。这里是设置最基本信息的地方。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <organization> <name>Codehaus Mojo</name> <url>http://mojo.codehaus.org</url> </organization> </project>
开发者
所有项目都包含在某个时间由一个人创建的文件。就像围绕项目的其他系统一样,参与项目的人在项目中也有利益关系。开发人员大概是项目核心开发的成员。请注意,虽然一个组织可能有许多开发人员(程序员)作为成员,但将他们全部列为开发人员并不是一种好的形式,而仅列出直接负责代码的人员。一个好的经验法则是,如果不应就项目联系此人,则无需在此处列出。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <developers> <developer> <id>jdoe</id> <name>John Doe</name> <email>jdoe@example.com</email> <url>http://www.example.com/jdoe</url> <organization>ACME</organization> <organizationUrl>http://www.example.com</organizationUrl> <roles> <role>architect</role> <role>developer</role> </roles> <timezone>America/New_York</timezone> <properties> <picUrl>http://www.example.com/jdoe/pic</picUrl> </properties> </developer> </developers> ... </project>
- id、name、email:这些对应于开发人员的 ID(可能是整个组织中的某个唯一 ID)、开发人员的姓名和电子邮件地址。
- organization , organizationUrl:您可能已经猜到了,它们分别是开发者的组织名称和 URL。
- 角色:A
role
应该指定该人负责的标准操作。就像一个人可以戴很多帽子一样,一个人可以戴多个roles
。 - timezone : 一个有效的时区 ID,例如
America/New_York
orEurope/Berlin
,或与开发人员居住的 UTC 的小时数(和分数)的数字偏移量,例如-5
or+1
。时区 ID 是首选,因为它们不受 DST 和时区偏移的影响。有关官方时区数据库和Wikipedia中的列表,请参阅IANA。 - properties:此元素是有关此人的任何其他属性的位置。例如,指向个人图像或即时消息句柄的链接。不同的插件可能会使用这些属性,或者它们可能只是供阅读 POM 的其他开发人员使用。
贡献者
贡献者就像开发人员一样,在项目的生命周期中扮演着辅助角色。也许贡献者发送了一个错误修复,或者添加了一些重要的文档。一个健康的开源项目可能拥有比开发人员更多的贡献者。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <contributors> <contributor> <name>Noelle</name> <email>some.name@gmail.com</email> <url>http://noellemarie.com</url> <organization>Noelle Marie</organization> <organizationUrl>http://noellemarie.com</organizationUrl> <roles> <role>tester</role> </roles> <timezone>America/Vancouver</timezone> <properties> <gtalk>some.name@gmail.com</gtalk> </properties> </contributor> </contributors> ... </project>
贡献者包含的元素集与没有元素的开发者相同id
。
环境设置
问题管理
这定义了使用的缺陷跟踪系统(Bugzilla、TestTrack、ClearQuest等)。尽管没有什么可以阻止插件将这些信息用于某事,但它主要用于生成项目文档。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <issueManagement> <system>Bugzilla</system> <url>http://127.0.0.1/bugzilla/</url> </issueManagement> ... </project>
持续集成管理
在过去的几年里,基于触发器或时间(例如,每小时或每天)的持续集成构建系统已经变得比手动构建更受欢迎。随着构建系统变得更加标准化,运行触发器这些构建的系统也变得更加标准化。尽管大部分配置取决于所使用的特定程序(Continuum、Cruise Control 等),但也有一些配置可能发生在 POM 中。Maven 已经捕获了通知程序元素集中的一些重复设置。通知程序是通知人们某些构建状态的方式。在以下示例中,此 POM 设置类型通知器mail
(表示电子邮件),并配置电子邮件地址以在指定触发器sendOnError
、sendOnFailure
和 notsendOnSuccess
或上使用sendOnWarning
。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <ciManagement> <system>continuum</system> <url>http://127.0.0.1:8080/continuum</url> <notifiers> <notifier> <type>mail</type> <sendOnError>true</sendOnError> <sendOnFailure>true</sendOnFailure> <sendOnSuccess>false</sendOnSuccess> <sendOnWarning>false</sendOnWarning> <configuration><address>continuum@127.0.0.1</address></configuration> </notifier> </notifiers> </ciManagement> ... </project>
邮件列表
邮件列表是与人们就项目保持联系的绝佳工具。大多数邮件列表都是针对开发人员和用户的。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <mailingLists> <mailingList> <name>User List</name> <subscribe>user-subscribe@127.0.0.1</subscribe> <unsubscribe>user-unsubscribe@127.0.0.1</unsubscribe> <post>user@127.0.0.1</post> <archive>http://127.0.0.1/user/</archive> <otherArchives> <otherArchive>http://base.google.com/base/1/127.0.0.1</otherArchive> </otherArchives> </mailingList> </mailingLists> ... </project>
- subscribe , unsubscribe:这些元素指定了用于执行相关操作的电子邮件地址。要订阅上面的用户列表,用户将向 user-subscribe@127.0.0.1 发送电子邮件。
- archive:此元素指定旧邮件列表电子邮件存档的 url(如果存在)。如果有镜像存档,可以在 otherArchives 下指定。
- post:用于发布到邮件列表的电子邮件地址。请注意,并非所有邮件列表都可以发布到(例如构建失败列表)。
单片机
SCM(软件配置管理,也称为源代码/控制管理或简而言之,版本控制)是任何健康项目不可或缺的一部分。如果您的 Maven 项目使用 SCM 系统(确实如此,不是吗?),那么您可以将这些信息放入 POM 中。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <scm> <connection>scm:svn:http://127.0.0.1/svn/my-project</connection> <developerConnection>scm:svn:https://127.0.0.1/svn/my-project</developerConnection> <tag>HEAD</tag> <url>http://127.0.0.1/websvn/my-project</url> </scm> ... </project>
- connection , developerConnection:这两个连接元素传达了一个是如何通过 Maven 连接到版本控制系统。如果连接需要 Maven 读取权限才能找到源代码(例如,更新),developerConnection 需要一个可以提供写入权限的连接。Maven 项目催生了另一个名为 Maven SCM 的项目,它为任何希望实现它的 SCM 创建了一个通用 API。最受欢迎的是 CVS 和 Subversion,但是,其他受支持的SCM列表也在不断增加。所有 SCM 连接都是通过一个通用的 URL 结构进行的。
scm:[provider]:[provider_specific]
其中 provider 是 SCM 系统的类型。例如,连接到 CVS 存储库可能如下所示:
scm:cvs:pserver:127.0.0.1:/cvs/root:my-project
- tag:指定此项目所在的标签。HEAD(意思是 SCM 根)是默认值。
- url:可公开浏览的存储库。例如,通过 ViewCVS。
先决条件
POM 可能具有某些先决条件才能正确执行。在 POM 4.0.0 中作为先决条件存在的唯一元素是maven
元素,它需要一个最小版本号。
在 Maven 3 中,使用Maven Enforcer Plugin 的requireMavenVersion
rule或其他构建时先决条件的规则。对于打包maven-plugin
,这仍然在运行时使用,以确保满足插件的最低 Maven 版本(但仅在引用插件的 pom.xml 中)。
在 Maven 2 中,这些先决条件也在构建时进行了评估:如果不满足这些先决条件,Maven 2 甚至在开始之前就会使构建失败。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <prerequisites> <maven>2.0.6</maven> </prerequisites> ... </project>
存储库
存储库是遵循 Maven 存储库目录布局的工件的集合。为了成为 Maven 存储库工件,POM 文件必须存在于结构$BASE_REPO/groupId/artifactId/version/artifactId-version.pom
中。$BASE_REPO
可以是本地(文件结构)或远程(基本 URL);其余的布局将是相同的。存储库作为收集和存储工件的地方而存在。每当项目依赖于工件时,Maven 将首先尝试使用指定工件的本地副本。如果该工件在本地存储库中不存在,它将尝试从远程存储库下载。POM 中的存储库元素指定要搜索的那些备用存储库。
存储库是 Maven 社区最强大的功能之一。默认情况下,Maven 在https://repo.maven.apache.org/maven2/搜索中央存储库。可以在 pom.xml `repositories` 元素中配置其他存储库。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <repositories> <repository> <releases> <enabled>false</enabled> <updatePolicy>always</updatePolicy> <checksumPolicy>warn</checksumPolicy> </releases> <snapshots> <enabled>true</enabled> <updatePolicy>never</updatePolicy> <checksumPolicy>fail</checksumPolicy> </snapshots> <name>Nexus Snapshots</name> <id>snapshots-repo</id> <url>https://oss.sonatype.org/content/repositories/snapshots</url> <layout>default</layout> </repository> </repositories> <pluginRepositories> ... </pluginRepositories> ... </project>
- 发布,快照:这些是每种类型的工件、发布或快照的策略。有了这两个集合,POM 就有能力在单个存储库中独立于其他类型更改每种类型的策略。例如,一个人可能决定只启用快照下载,可能是出于开发目的。
- enabled:
true
或者false
是否为相应的类型(releases
或snapshots
)启用此存储库。 - updatePolicy:此元素指定尝试更新的频率。Maven 会将本地 POM 的时间戳(存储在存储库的 maven-metadata 文件中)与远程进行比较。选项包括:
always
、daily
(默认)、interval:X
(其中 X 是以分钟为单位的整数)或never
. - checksumPolicy:当 Maven 将文件部署到存储库时,它也会部署相应的校验和文件。您的选项是
ignore
、fail
或warn
缺少或不正确的校验和。 - layout:在上面对存储库的描述中,提到它们都遵循一个共同的布局。这大多是正确的。Maven 2 引入的布局是 Maven 2 和 3 使用的存储库的默认布局;然而,Maven 1.x 有不同的布局。使用此元素指定 if 是
default
还是legacy
。
插件库
存储库是两种主要类型工件的所在地。第一个是用作其他工件的依赖项的工件。这些是驻留在中央的大多数工件。另一种类型的工件是插件。Maven 插件本身就是一种特殊的工件。正因为如此,插件存储库可能与其他存储库分开(尽管我还没有听到有说服力的理由这样做)。在任何情况下,pluginRepositories
元素块的结构都与元素相似repositories
。每个pluginRepository
元素都指定了 Maven 可以找到新插件的远程位置。
分销管理
分发管理就像听起来一样:它管理整个构建过程中生成的工件和支持文件的分发。首先从最后一个元素开始:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <distributionManagement> ... <downloadUrl>http://mojo.codehaus.org/my-project</downloadUrl> <status>deployed</status> </distributionManagement> ... </project>
- downloadUrl:是另一个 POM 可以指向的存储库的 URL,以获取此 POM 的工件。用最简单的话来说,我们告诉 POM 如何上传它(通过 repository/url),但是公众可以从哪里下载呢?这个元素回答了这个问题。
- 状态:警告!地位就像窝里的小鸟,人的手绝对不能碰!这样做的原因是 Maven 将在项目传输到存储库时设置项目的状态。其有效类型如下。
- none:无特殊状态。这是 POM 的默认设置。
- convert :存储库的经理将此 POM 从早期版本转换为 Maven 2 。
- 合作伙伴:此工件已与合作伙伴存储库同步。
- 已部署:迄今为止最常见的状态,这意味着该工件是从 Maven 2 或 3 实例部署的。这是您使用命令行部署阶段手动部署时得到的结果。
- 已验证:此项目已通过验证,应视为已完成。
存储库
repositories 元素在 POM 中指定 Maven 可以下载远程工件以供当前项目使用的位置和方式,而 distributionManagement 指定该项目在部署时将在何处(以及如何)到达远程存储库。如果未定义快照存储库,则存储库元素将用于快照分发。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <distributionManagement> <repository> <uniqueVersion>false</uniqueVersion> <id>corp1</id> <name>Corporate Repository</name> <url>scp://repo/maven2</url> <layout>default</layout> </repository> <snapshotRepository> <uniqueVersion>true</uniqueVersion> <id>propSnap</id> <name>Propellors Snapshots</name> <url>sftp://propellers.net/maven</url> <layout>legacy</layout> </snapshotRepository> ... </distributionManagement> ... </project>
- id , name :
id
用于在众多存储库中唯一标识此存储库,并且name
是人类可读的形式。 - uniqueVersion:唯一版本采用
true
orfalse
值来表示部署到此存储库的工件是否应该获得唯一生成的版本号,或者使用定义为地址的一部分的版本号。 - url:这是存储库元素的核心。它指定了用于将构建的工件(以及 POM 文件和校验和数据)传输到存储库的位置和传输协议。
- layout:这些类型和用途与 repository 元素中定义的 layout 元素相同。它们是
default
和legacy
。
站点分布
不仅仅是分发到存储库,distributionManagement
还负责定义如何部署项目的站点和文档。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <distributionManagement> ... <site> <id>mojo.website</id> <name>Mojo Website</name> <url>scp://beaver.codehaus.org/home/projects/mojo/public_html/</url> </site> ... </distributionManagement> ... </project>
- id、name、url:这些元素与上面元素中的对应元素相似
distributionManagement
repository
。
搬迁
<project xmlns="http://maven.apache.org/POM/4.0.0"1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <distributionManagement> ... <relocation> <groupId>org.apache</groupId> <artifactId>my-project</artifactId> <version>1.0</version> <message>We have moved the Project under Apache</message> </relocation> ... </distributionManagement> ... </project>
项目不是静态的;它们是活的东西(或垂死的东西,视情况而定)。随着项目的发展,一个常见的事情是他们被迫搬到更合适的地方。例如,当您的下一个非常成功的开源项目转移到 Apache 的保护伞下时,最好提醒用户该项目正在重命名为org.apache:my-project:1.0
. 除了指定新地址之外,提供解释原因的消息也是一种很好的形式。
简介
POM 4.0 的一个新特性是项目能够根据正在构建的环境更改设置。一个profile
元素既包含一个可选的激活(配置文件触发器),也包含在该配置文件已激活时要对 POM 进行的一组更改。例如,为测试环境构建的项目可能指向与最终部署不同的数据库。或者可以根据使用的 JDK 版本从不同的存储库中提取依赖项。profile的元素如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <profiles> <profile> <id>test</id> <activation>...</activation> <build>...</build> <modules>...</modules> <repositories>...</repositories> <pluginRepositories>...</pluginRepositories> <dependencies>...</dependencies> <reporting>...</reporting> <dependencyManagement>...</dependencyManagement> <distributionManagement>...</distributionManagement> </profile> </profiles> </project>
激活
激活是配置文件的关键。配置文件的强大之处在于它仅在某些情况下修改基本 POM 的能力。这些情况是通过一个activation
元素指定的。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> ... <profiles> <profile> <id>test</id> <activation> <activeByDefault>false</activeByDefault> <jdk>1.5</jdk> <os> <name>Windows XP</name> <family>Windows</family> <arch>x86</arch> <version>5.1.2600</version> </os> <property> <name>sparrow-type</name> <value>African</value> </property> <file> <exists>${basedir}/file2.properties</exists> <missing>${basedir}/file1.properties</missing> </file> </activation> ... </profile> </profiles> </project>
在 Maven 3.2.2 之前 激活发生在满足一个或多个指定条件时。当遇到第一个肯定结果时,处理停止并且配置文件被标记为活动。从 Maven 3.2.2 开始,当所有指定条件都满足时,就会发生激活。
- jdk:在元素
activation
中有一个内置的、以 Java 为中心的检查。jdk
如果测试在与给定前缀匹配的 jdk 版本号下运行,这将激活。在上面的例子中,1.5.0_06
将匹配。还支持范围。有关支持的范围的更多详细信息,请参阅maven-enforcer-plugin。 - os:该
os
元素可以定义一些操作系统特定的属性,如上所示。有关 OS 值的更多详细信息,请参阅 maven-enforcer-plugins RequireOS Rule。 - property:如果 Maven 检测到相应对
profile
的系统属性和命令行属性(可以在 POM 中取消引用的值),则将激活。${name}
name=value
- file:最后,给定的文件名可能会激活文件
profile
的existence
,或者如果它是missing
. 注意:此元素的插值仅限于${basedir}
系统属性和请求属性。
activation
元素不是profile
激活a的唯一方式。settings.xml
文件的元素activeProfile
可能包含配置文件的id
. 它们也可以通过命令行通过-P
标志后的逗号分隔列表显式激活(例如-P codecoverage
)。
要查看哪个配置文件将在某个构建中激活,请使用 maven-help-plugin
.
mvn help:active-profiles
BaseBuild 元素集 (重新访问)
如上所述,这两种类型的构建元素的原因在于,配置文件配置构建目录或扩展名没有意义,因为它在 POM 的顶层中所做的那样。不管项目是在什么环境下构建的,有些值会保持不变,比如源代码的目录结构。如果您发现您的项目需要为不同的环境保留两套代码,那么研究将项目重构为两个或多个单独的项目可能是明智的。
最终的
Maven POM 很大。然而,它的大小也证明了它的多功能性。至少可以说,将项目的所有方面抽象为单个工件的能力非常强大。数十个不同的构建脚本和关于每个单独项目的分散文档的日子已经一去不复返了。与构成 Maven 星系的 Maven 的其他明星一起——定义明确的构建生命周期、易于编写和维护的插件、集中的存储库、系统范围和基于用户的配置,以及越来越多的工具来使开发人员工作更容易维护复杂的项目——POM 是大而明亮的中心。
本指南的各个方面最初发表在Maven 2 Pom Demystified中。