Java Maven POM配置参考
介绍
什么是POM?
POM代表“项目对象模型”。它是一个名为pom.XML
的文件中保存的Maven项目的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>
一个简单的配置示例
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.study</groupId>
<artifactId>kafka-meter</artifactId>
<version>1.0</version>
<description>Kafka plugin for JMeter</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<apache.jmeter.core>5.4.1</apache.jmeter.core>
<org.log4j>2.11.1</org.log4j>
<sf.kafka.api.core.version>1.18.2</sf.kafka.api.core.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.jmeter</groupId>
<artifactId>ApacheJMeter_core</artifactId>
<version>${apache.jmeter.core}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${org.log4j}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${org.log4j}</version>
</dependency>
<dependency>
<groupId>com.sf.kafka</groupId>
<artifactId>sf-kafka-api-core</artifactId>
<version>${sf.kafka.api.core.version}</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
</project>
基础配置(The Basics)
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-project</artifactId>
<version>1.0</version>
</project>
Maven坐标(Coordinates)
上面定义的POM是Maven允许的最小配置。groupId:artifactId:version
都是必需字段(不过,如果从父级继承groupId
和version
,则不需要显式定义它们-稍后将详细介绍继承)。这三个字段的作用非常像一个地址和时间戳。这标志着仓库中的一个特定位置,就像Maven项目的坐标系一样:
- groupId: 这在一个组织或项目中通常是独一无二的。例如,所有的核心Maven工件都应该位于
groupId
org.apache.Maven
下。groupId
不一定使用点符号,例如junit项目。请注意,点标记的groupId
不必与项目包含的包结构相对应。然而,这是一个很好的做法。当存储在仓库中时,该组的行为与操作系统中的Java包结构非常相似。点被操作系统特定的目录分隔符(如Unix中的“/”)所取代,后者成为Base仓库的相对目录结构。在给定的示例中,org.codehaus.mojo
组位于目录$M2_REPO/org/codehaus/mojo
中。 - artifactId:
artifactId
通常是项目的名称。尽管groupId
很重要,但组内的人很少在讨论中提到groupId
(他们通常都是同一个ID,例如MojoHaus项目groupId:org.codehaus.mojo
)。artifactId
和groupId
一起创建了一个Key,将这个项目与世界上其他所有项目区分开来(至少,它应该 😃)。artifactId
和groupId
完全定义了工件在仓库中的存储区。在上述项目中,my-project
位于$M2_REPO/org/codehaus/mojo/my-project
。 - version: 用于以区分项目和工件版本。
my-project
版本 1.0文件位于目录结构$M2_REPO.org/codehaus/mojo/my-project/1.0
中。
上面给出的三个元素指向一个项目的特定版本,让Maven知道我们在与谁打交道,以及在其软件生命周期中我们需要它们的时间。
打包(Packaging)
现在我们有了groupId:artifactId:version
的地址结构,还有一个标准标签可以给我们一个真正完整的东西:那就是项目的packaging
。上述示例中定义的org.codehaus.mojo:my project:1.0
的示例POM将被打包为一个jar
文件。我们可以通过定义不同的packaging
将其变成一个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>
当没有声明任何packaging
时,默认为jar
。当前的核心packaing
值为:pom
、jar
、maven-plugin
、ejb
、war
、ear
、rar
。这些定义了在特定包结构的每个相应构建生命周期阶段执行的目标的默认列表:请参阅Plugin Bindings for default lifecycle Reference详细信息。
POM关系(POM Relationships)
依赖(Dependencies)
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可以管理的依赖关系。
不幸的是,有时项目无法从central Maven 仓库库下载。例如,一个项目可能依赖于
例如,一个项目可能依赖于一个拥有封闭源代码许可证的jar,该许可证阻止它位于central仓库中。有三种方法可以处理这种情况。
-
使用安装插件在本地安装依赖项。该方法是最简单的推荐方法。例如:
mvn install:install-file -Dfile=non-maven-proj.jar -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1 -Dpackaging=jar
请注意,地址仍然是必需的,只是这次使用命令行,安装插件将为您创建一个具有给定地址的POM
-
-
创建自己的仓库并发布依赖。这是拥有内联网的公司最喜欢的方法,需要能够让每个人都保持同步。Maven有一个名为
deploy:deploy-file
的目标,它类似于install:install-file
目标。 -
将依赖关系范围设置为
system
并定义systemPath
。但是,不建议这样做
-
classifier
classifier区分从相同POM构建但内容不同的工件。它是一些可选的任意字符串,如果有值的话,它会被附加到工件名称中版本号后面。
以项目为例来说明这个元素的动机。假设有个项目,该项目提供了一个以Java 11为目标的工件,但同时也提供了仍然支持Java 1.8的工件。第一个工件可以配备有
classifier
jdk11
,第二个工件配备jdk8
,这样客户端可以选择使用哪一个。classifier
的另一个常见用法是将次要工件附加到项目的主要工件上。如果浏览Maven center仓库库,你会注意到classifier
sources
和javadoc
用于部署项目源代码和API文档以及打包的类文件 -
type
对应于所选的依赖项类型。默认为jar
。虽然它通常表示依赖项文件名上的扩展名,但情况并非总是如此:一个类型可以映射到不同的扩展名和classifier。类型通常与所使用的packaging相对应,尽管情况并非总是如此。类型的一些示例值jar
, ejb-client
和test-jar
:请参见默认工件处理程序以获取列表。新类型可以由将extensions
设置为true
的插件定义,因此这不是一个完整的列表
-
scope
这个元素指的是手头任务(编译和运行时、测试等)的类路径,以及如何限制依赖项的传递性。有五个作用域可用:
- compile - 这是默认作用域,如果未指定则使用默认值。编译依赖项在所有类路径中都可用。此外,这些依赖关系会传播到依赖项目。
- provided - 和compile很像,但表示你希望JDK或容器在运行时提供依赖关系。它仅在编译和测试类路径上可用,并且不可传递。
- runtime - 此作用域表示该依赖项不是编译所必须的,而是执行依赖项。它在运行时和测试类路径中,但不在编译类路径中。
- test - 此作用域表示此依赖项不是应用程序的正常使用所需,仅适用于测试编译和执行阶段。它不是传递性的。
- system - 此作用域类似
provided
。只是你必须提供显式包含它的JAR。工件始终可用,并且不会在仓库中查找
-
systemPath
仅依赖项scope
为system
时使用。否则,如果设置了此元素,则将构建失败。此路径必须是绝对路径,因此建议使用属性来指定特定于机器的路径(查看下文的 properties
获取更多 ),例如${java.home}/lib
。由于假设系统作用域依赖项是事先安装的,因此Maven不会检查项目的仓库,而是检查以确保文件存在,如果不存在,Maven将构建失败,并建议你手动下载并安装它。
-
optional
当此项目本身是依赖项时,将依赖项标记为可选。例如,假设一个项目
A
依赖于项目B
来编译一部分可能在运行时不使用的代码,那么我们可能不需要所有项目都使用项目B
。因此,如果项目X
添加项目A
作为自己的依赖项,那么Maven根本不需要安装项目B
。象征性地,如果=>
表示必需的依赖项,而-->
表示可选,构建A
时有A=>B
,但构建X
时则是X=>A-->B
。简而言之,
optional
让其他项目知道,当你使用此项目时,不需要此依赖项也能正常工作。
依赖版本需求说明(Dependency Version Requirement Specification)
依赖项version
元素定义了用于计算依赖项版本的版本要求。软需求可以被依赖关系图中其他地方相同工件的不同版本所取代。硬需求要求特定的一个或多个版本,并凌驾于软需求之上。如果没有满足该工件所有硬需求的依赖项版本,则构建失败。
版本需求具有以下语法:
-
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.2和1.3)之间的任意版本(硬需求)。 -
[1.0,2.0)
: 1.0 <= x < 2.0; 要求1.0到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选择每个项目的最高版本,以满足该项目依赖项的所有硬性要求。如果没有一个版本能够满足所有的硬性要求,那么构建就会失败。
版本顺序说明(Version Order Specification):
如果版本字符串为语法正确的Semantic Versioning 1.0.0版本号,那么在几乎所有情况下,版本比较都遵循该规范中概述的优先级规则。这些版本是常见的字母数字ASCII字符串,如2.15.2-alpha。更准确地说,如果要比较的版本号都与语义版本规范中BNF语法中的“有效semver”生成相匹配,则情况也是如此。Maven不考虑该规范所隐含的任何语义。
重要:这仅适用于Semantic Versioning 1.0.0。Maven版本顺序算法与Semantic version2.0.0不兼容。特别是,Maven没有对加号进行特殊处理,也没有考虑构建标识符。
当版本字符串不遵循Semantic Versioning时,需要一组更复杂的规则。Maven坐标被分割为点之间的标记('.
'),hyphe
Maven坐标按点('.
')、连字符('-
'),数字和字符之间的过渡之间的标记(token)进行拆分。分隔符将被记录并将对顺序产生影响。数字和字符之间的过渡相当于连字符。空的标记将替换为“0
”。这给出了一系列带有“.
”或“-
”前缀的版本号(数字标记)和版本限定符(非数字标记)(官方原文:The Maven coordinate is split in tokens between dots ('.
'), hyphens ('-
') and transitions between digits and characters. The separator is recorded and will have effect on the order. A transition between digits and characters is equivalent to a hyphen. Empty tokens are replaced with "0
". This gives a sequence of version numbers (numeric tokens) and version qualifiers (non-numeric tokens) with ".
" or "-
" prefixes)
拆分和替换示例:
1-1.foo-bar1baz-.1
->1-1.foo-bar-1-baz-0.1
然后,从版本的末尾开始,对后面的“null”值(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
版本顺序是这个带前缀的token序列上的“词典顺序”,带有匹配前缀的较短token,填充了足够多的的“null”值,与较长的token长度相同。填充的“null”值取决于其他版本的前缀:0表示“.”,"" 代表 '-'。带前缀的token顺序为:
-
如果前缀相同,则比较token:
-
字标型token按自然顺序排序。
-
非数字型token(“限定符”)按字母顺序排序,除了下token按此顺序排列在前:
"
alpha
" < "beta
" < "milestone
" < "rc
" = "cr
" < "snapshot
" < "" = "final
" = "ga
" < "sp
"- 当其后直接跟数字时,"
alpha
", "beta
" 和"milestone
"可以分别缩写为"a", "b"和"m"
- 当其后直接跟数字时,"
-
-
否 "
.qualifier
" = "-qualifier
" < "-number
" < ".number
" -
alpha
=a
<<> = b
<<<milestone>> =m
<> = cr
<<<snapshot>> '<<<>>' =final
=ga
=release
<sp
建议遵循semver规则,不建议使用某些修饰:
- '
alpha
', 'beta
', 和'milestone
' 修饰符优先于 'ea
' 和'preview
'. - '
1.0.0-RC1
'' 优先于'1.0.0.RC1
'. - 不推荐使用 '
CR
'限定符,改用'RC
'。 - 不建议使用 '
final
', 'ga
'和'release
' 限定符 - 不建议使用 '
SP
' 限定符。增加补丁版本号(patch version)
最终结果示例:
-
"
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
" (移除末尾"null"值) -
"
1-sp
" > "1-ga
" -
"
1-sp.1
" > "1-ga.1
" -
"
1-sp-1
" < "1-ga-1
" = "1-1
" (每个连字符后面的"null"值) -
"
1-a1
" = "1-alpha-1
"注意:与一些设计文档中所述的相反,对于版本顺序,snapshot与release或任何其他限定符没有区别对待。
注意:由于
2.0-rc1
<2.0
,版本要求[1.0,2.0)
不包括2.0
但包括2.0-rc1
,这与大多数人的预期相反。此外,Gradle对它的解释不同,导致同一POM的依赖树不同。如果打算将其限制为1.*版本,则更好的版本号要求是[1,1.9999999)
。
排除
限制依赖项的可传递依赖项有时很有用。依赖项可能具有错误指定的作用域,或者与项目中的其他依赖项冲突的依赖项。exclusions
告诉Maven不要在classpath中包含指定的工件,即使它是该项目的一个或多个依赖项的依赖项(传递依赖项)。例如, maven-embedder
依赖于maven-core
。假设您想依赖maven-embedder
,但不想在classpath中包含maven-core
或其依赖项,那么在声明依赖 maven-embedder
的元素中添加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>3.9.3</version>
<exclusions>
<exclusion>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
</exclusion>
</exclusions>
</dependency>
...
</dependencies>
...
</project>
这只会从这个依赖项中删除指向maven-core
的路径。如果maven-core
在POM的其他地方作为直接或传递依赖出现,那么它仍然可以添加到classpath径中。
通配符排除,很容易排除依赖项的所有可传递依赖项。在以下情况中,假设你正在使用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.8.6</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
...
</dependencies>
...
</project>
- exclusions:
exclusions
包含一个或多个exclusion
元素,每个元素都包含表示要排除的依赖项的groupId
和artifactId
。与可能安装和使用,也可能不安装和使用的optional
不同,exclusions
会主动从依赖树中移除工件。
继承
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>
Now we may add values to the parent POM, which will be inherited by its children. Most elements from the parent POM are inherited by its children, including
对于parent和aggregation(多模块)项目,要求packaging
类型为pom
。这些类型定义了绑定到一组生命周期阶段的目标。例如,如果packaging
类型是jar
,那么packaging
阶段将执行jar:jar
目标。现在,我们可以为parent
添加值,该值将由其子代继承。parent
的大多数元素由其子代继承,包括:
- groupId
- version
- description
- url
- inceptionYear
- organization
- licenses
- developers
- contributors
- mailingLists
- scm
- issueManagement
- ciManagement
- properties
- dependencyManagement
- dependencies
- repositories
- pluginRepositories
- build
- plugin executions with matching ids
- plugin configuration
- etc.
- reporting
- profiles
值得注意是以下元素不被继承:
-
artifactId
-
name
-
prerequisites
<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的一个意符,实现在搜索本地和远程仓库之前,首先搜索为父项目提供的路径,即relativePath
设置的值。
Super 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
并在命令行上执行:mvn help:effective-pom
来了解Super POM如何影响你的项目对象模型
依赖管理
除了继承某些顶级元素外,parent
还拥有一些元素,可以为子POM和传递依赖项配置值。其中一个要素是dependencyManagement
。
-
dependencyManagement
:由POM用来帮助管理其所有子级的依赖关系信息。如果my-parent
使用dependencyManagement
定义对junit:junit:4.12
的依赖,那么从这个项目继承的POM设置他们的依赖项时可以仅提供groupId=junit
和artifactId=junit
,version
将被Maven填充为父项目设置的版本。这种方法的好处是显而易见的。可以集中在一个中心位置设置依赖关系详细信息,并传播到所有继承的POM。请注意,从可传递依赖项合并的工件的版本和作用域也由依赖项管理部分中的版本规范控制。这可能会导致意想不到的后果。考虑一个项目使用两个依赖项
dep1
和dep2
的情况。dep2
反过来也使用dep1,并且需要特定的最低版本才起作用。如果随后使用dependencyManagement
指定较旧版本,dep2
将被迫使用较旧版本,因此失败。因此,您必须小心检查整个依赖树,以避免出现此问题;mvn dependency:tree
很有帮助。
聚合(或多模块)
A project with modules is known as a multi-module, or aggregator project. Modules are projects that this POM lists, and are executed as a group. A pom
packaged project may aggregate the build of a set of projects by listing them as modules, which are relative paths to the directories or the POM files of those projects.
包含模块的项目称为多模块或聚合项目。模块是本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将对模块进行拓扑排序,这样依赖关系总是在依赖模块之前构建。
属性(Properties)
Properties are the last required piece to understand POM basics. Maven properties are value placeholders, like properties in Ant. Their values are accessible anywhere within a POM by using the notation ${X}
, where X
is the property. Or they can be used by plugins as default values, for example:
properties
是理解POM基础知识所需的最后一部分。Maven properties
是值占位符,类似于Ant中的properties
。通过使用符号${X}
,可以在POM中的任何位置访问properties
的值,其中X
是property
。或许它们可以被插件用作默认值,例如:
<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>
properties
具有5种不同的风格:
-
env.X
:在属性变量前加前缀env.
将返回shell环境变量。例如,${env.PATH}
将返回PATH
环境变量值。注意:虽然环境变量本身在Windows上不区分大小写,但
properties
的查找是区分大小写的。换句话说,虽然Windows shell为%PATH%
和%Path%
返回相同的值,但Maven区分${env.PATH}
和${env.Path}
。为了可靠性,将环境变量的名称都标准化为大写。 -
project.x
: POM中点分路径将包含相应元素的值。例如:通过${project.version}
获取version
属性值1.0
-
settings.x
:settings.xml
点分路径将包含相应元素的值。例如:通过${settings.offline}
获取offline
属性值false
-
Java系统属性:所有可通过
Java.lang.System.getProperties()
访问的属性都可用作POM属性,比如${java.home}
-
x
: 在POM中的元素内设置。 <properties><someVar>value</someVar></properties>
的值value
可以用作${someVar}
。
构建设置
Build
根据POM 4.0.0 XSD,build
元素在概念上分为两个部分:一个是BaseBuild
类型,它包含两个build
元素共有的一系列元素(project
下的顶级build
元素和profiles
下的build
元件,如下所述);另一个是Build
类型,包含BaseBuild
元素集以及用于顶层定义的更多元素。
注意:这些不同的build
元素可以表示为“Project Build”和“Profile 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
:POM中两个build
元素之间的基本元素集。
<build>
<defaultGoal>install</defaultGoal>
<directory>${basedir}/target</directory>
<finalName>${artifactId}-${version}</finalName>
<filters>
<filter>filters/filter1.properties</filter>
</filters>
...
</build>
-
defaultGoal: 如果什么都没有给定时,默认执行的目标(goal)或阶段(phase)。如果给定了一个目标,那么应该和在命令行中一样定义它(例如
jar:jar
)。如果定义了一个阶段(例如install),情况也是如此。 -
directory: 这是构建将转储其文件,或者用Maven的术语,其构建目标的目录。它恰当地默认为
${basedir}/target
。 -
finalName: 这是绑定项目最终被构建的名称(没有文件扩展名,例如:
my-project-1.0.jar
)。默认为${artifactId}-${version}
。然而,术语finalName
有点用词不当,因为构建绑定项目的插件完全有权忽略、修改这个名称(通常不会)。例如,如果maven-jar-plugin
被配置为给某个jar一个test
的classifier
,那么上面定义的jar实际将被构建为my-project-1.0-test.jar
。 -
filter:定义
*.properties
文件,该文件包含应用于接受其设置的资源的属性列表(如下所述)。换句话说,filter
文件中定义的 "name=value
"对将在构建时替换资源中的${name}
字符串。上面的示例定义了位于filters/
目录下的filter1.properties
文件。Maven的默认filter目录为${basedir}/src/main/filters/
。要更全面地了解filter是什么以及它们可以做什么,请查看快速入门指南
-
For a more comprehensive look at what filters are and what they can do, take a look at the quick start guide.
*.properties
files that contain a list of properties that apply to resources which accept their settings (covered below). In other words, the "
name=value
" pairs defined within the filter files replace
${name}
strings within resources on build. The example above defines the
filter1.properties
file under the
filters/
directory. Maven's default filter directory is
${basedir}/src/main/filters/
.
For a more comprehensive look at what filters are and what they can do, take a look at the quick start guide.
资源(Resources)
build
元素的另一个功能是指定项目中资源的位置。资源不是(通常)代码。它们不被编译,但是需要捆绑在项目中或用于其它各种需要(如代码生成)。
例如,某个Plexus项目需要一个位于META-INF/plexus
目录中的configuration.xml
文件(该文件指定容器的组件配置)。尽管我们可以很容易地将此文件放置在src/main/resources/META-INF/plexus
中,但我们希望为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: 指定用于放置来自构建的资源集的目录结构。
targetPath
默认为基目录(base目录)。通常为将打包在JAR中的资源指定的targetPath
为META-INF
。 - filtering:
true
或者false
, 表示是否要为此资源启用过滤。请注意,过滤器*.properties
文件不定义也可进行过滤-资源也可以使用默认情况下在POM中定义的properties
(如${project.version}
),使用-D
标志(例如,"-Dname
=value
")传递到命令行或由properties
元素显式定义的属性。 - directory:
${basedir}/src/main/resources
.此元素的值定义了资源的查找位置。构建的默认目录是${basedir}/src/main/resources
。 - includes: 指定要作为资源包含在指定目录下的文件,使用
*
作为通配符 - excludes: 与
includes
的结构相同,不过用于指定要忽略的文件。如果include
和exclude
之间如果存在冲突,则exclude
“获胜”。 - testResources:
testResources
元素块包含testResource
元素。它们的定义类似于resource
元素,不过是在测试阶段使用。一个区别是,项目的默认(Super POM定义的)测试资源目录是${basedir}/src/test/resources
。测试资源不被发布。
插件(Plugins)
<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
,是否加载此插件的扩展。默认情况下为false
。 -
inherited:
true
或者false
,这个插件配置是否应该应用于继承自这个插件的POM。默认true
. -
configuration: 这是特定于单个插件的。插件Mojo可能期望的任何属性(这些是Java Mojo bean中的getter和setter)都可以在这里指定。在上面的例子中,我们将
maven-jar-plugin
Mojo中classifier
属性设置为test。值得注意的是,所有配置元素,无论它们在POM中的哪个位置,都旨在将值传递给另一个底层系统,例如插件。换句话说:POM模式从来没有明确要求configuration
元素中的值,但插件目标完全有权要求configuration
值。如果你的POM声明了一个parent,它将从parent的
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>
假设以下为某个项目的插件配置,该项目使用上述POM作为其parent
<plugin> <groupId>my.group</groupId> <artifactId>my-plugin</artifactId> <configuration> <items> <item>child-1</item> </items> <properties> <childKey>child</childKey> </properties> </configuration> </plugin>
默认行为是根据元素名称合并configuration 元素的内容。如果子POM具有特定元素,则其值将成为有效值。如果子POM没有元素,但父POM有,则父值将成为有效值。请注意,这纯粹是对XML的操作;不涉及插件本身的代码或配置,只涉及元素,而不是它们的值。
将这些规则应用到示例中,得到以下配置:
<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
可以通过向
configuration
元素的子元素添加属性--combine.children
和combing.self
,来控制子POM如何从父POM继承配置。在子POM中使用这些属性可以控制Maven如何将父级的插件配置与子级的显式配置相结合。以下是带有这两个属性示例的子POM配置
<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"
,如果同时配置了则combine.self="override"
。注意,这些属性只应用于它们声明的配置元素,而不会传递到嵌套元素。也就是说,如果子POM中的
item
元素的内容是一个复杂的结构,而不是文本,那么它的子元素仍将受到默认合并策略的约束,除非它们本身用属性标记。子POM会从父POM继承
combine.*
属性。将这些属性添加到父POM时要小心,因为这可能会影响子POM或子孙POM。
-
-
dependencies: 在POM中可以看到很多依赖项,它们是所有
plugins
元素块下的一个元素。依赖项具有与basebuild
下相同的结构和功能。这种情况下的主要区别在于,它们不再作为项目的依赖项应用,而是作为所属插件的依赖项来应用。这样做的功能是更改插件的依赖项列表,可能是通过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: /home/jenkins/82467a7c/workspace/aven_maven-box_maven-site_master/target</echo> </tasks> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
-
id: 此
execution
块唯一标识。当阶段运行时,它将以[plugin:target-execution:id]
的形式显示。在本例中:[antrun:run execution:echodir]
-
goals: 包含一个单数元素(
goal
)列表。在这种情况下,由这个execution
块指定的插件goals
列表 -
phase:设置目标列表将在其中执行的阶段。这是一个非常强大的选项,允许将任何目标绑定到构建生命周期中的任何阶段,从而改变Maven的默认行为
-
inherited: 类似上面的
inherited
元素,设置为false
将禁止Maven将此execution
传递给其子级。此元素仅对父POM有意义 -
configuration: 与上面的
configuration
相同,除了将配置限制在这个特定的目标列表中,而不是插件下的所有目标
-
插件管理(Plugin Management)
- pluginManagement: 插件管理以和上文
plugins
几乎相同的方式包含插件元素,只是它不是为这个特定的项目构建配置插件信息,而是旨在配置从这个项目构建继承的项目构建。然而,这只配置在子POM或当前POM中plugins
元素实际引用的插件。子POM们完全有权覆盖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和所有将maven-jar-plugin
添加到构建中的继承POM也将获取 pre-process-classes
execution
。因此,与其在每个子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>
Build元素集(The Build Element Set)
目录(Directories)
目录元素集位于父级build
元素中,该元素作为一个整体为POM设置了各种目录结构。由于它们不存在于profiles
build
中,因此profiles
无法更改这些内容。
<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中使用,并且已经过时。
扩展(Extensions)
扩展为要在此构建中使用的工件列表。它们将包含在正在运行的构建的classpath中。它们可以对构建过程开启扩展(例如为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>
报告(Reporting)
<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>
......
更多配置参考,请查阅官方文档