本节来学习下Maven的pom文件。
什么是POM文件
项目对象模型或POM是Maven中的基本工作单元。它是一个XML文件,包含Maven用于构建项目的项目信息和配置细节。它包含大多数项目的默认值。例如构建目录,target
目录,源代码目录src/main/java
,测试源代码目录src/test/java
等。在执行任务或目标时,Maven在当前目录中查找pom文件。读取pom,获取需要的配置信息,然后执行目标。
在pom中可以指定的信息有项目依赖项、执行的插件或目标、构建配置文件等。还可以指定项目版本、描述、开发人员、邮件列表等其他信息。
Super POM
Super POM是Maven的默认POM。除非显示设置,否则所有的pom都扩展Super POM。这意味着Super POM中指定的配置,将由我们创建的项目的pom继承。Super POM的代码片段参照官网。
Minimal POM
POM的配置的最低要求如下:
- project root
- modelVersion - 需要被设置成4.0.0
- groupId - 项目组织的ID
- artifactId - 项目的ID
- version - 项目的版本号
示例:
|
|
POM需要配置其groupId、artifactId和version。这三个值构成了项目的完全限定名,以<groupId>:<artifactId>:<version>
的形式出现。对于上面的例子,它的完全限定名是“com.mycompany.app:my-app:1”。
如果没有指定配置细节,Maven将使用它们的默认值,这些默认值之一是打包类型。每个Maven项目都有一种打包类型如果POM中没有指定它,那么将使用默认值“jar”。
此外,我们看到最小POM中没有指定存储库。如果使用最小POM构建项目,它将继承Super POM中的存储库配置。因此,当Maven看到最小POM中的依赖项时,它知道这些依赖项将从Super POM指定的路径http://repo.maven.apache.org/maven2 下载。
项目继承
POM中合并的元素如下:
- dependencies
- developers and contributors
- plugin lists (including reports)
- plugin executions with matching ids
- plugin configuration
- resources
Super POM是项目继承的一个例子,但是我们也可以通过指定pom中的parent标签来引入自己的父POM,如下面的示例所示。
Example 1
场景
例如,我们重用以前的项目com.mycompany.app:my-app:1,并且引入另一个项目com.mycompany.app:my-module:1。
|
|
让我们指定他们的目录结构如下:
|
|
注意:my-module/pom.xml
是com.mycompany.app:my-module:1的POM,而pom.xml
是com.mycompany.app:my-app:1的POM。
解决方案
现在,我们将com.mycompany.app:my-app:1转变为com.mycompany.app:my-module:1的父项目,修改com.mycompany.app:my-module:1’的pom.xml如下:
|
|
注意,我们现在有了一个添加的部分,parent标签。这个部分允许指定哪个项目是我们POM的父项目,我们通过指定父POM的完全限定名来实现这一点。过这个设置,我们的模块现在可以继承父POM的一些属性。
或者,如果我们希望模块的groupId或version与父模块相同,可以删除模块POM中的groupId和version标签:
|
|
Example 2
场景
尽管如果父项目已经安装到本地存储库中,或者在特定的目录结构中(模块的目录为父POM的子目录),上面的配置方式是可行的。但是如果父项目还没安装,并且目录结构与下面的示例一样,该怎么办呢?
|
|
解决方案
要处理这个目录结构,需要将<relativePath>
标签添加到parent部分:
|
|
顾名思义,它是模块pom.xml对于父pom.xml的相对路径。
项目聚合
项目聚合类似于项目继承。但它不是从模块指定父POM,而是从父POM指定模块。通过这样,父项目知道了它的模块,如果对父项目调用Maven命令,那么命令也会执行到父项目的各个模块。要进行项目聚合,需要做如下:
- 将父项目的打包类型改为pom
- 在父POM中指定模块
Example 3
场景
沿用上面的POM和目录结构:
com.mycompany.app:my-app:1的POM
|
|
com.mycompany.app:my-module:1的POM
|
|
目录结构如下:
|
|
The Solution
如果要将my-module聚合到my-app中,只需要修改my-app即可。
|
|
如上,增加了<packaging>
和<modules>
部分。现在,每当Maven命令处理com.mycompany.app:my-app:1时,相同的命令会在com.mycompany.app:my-module:1 上运行。另外,一些命令以不同的方式处理命令聚合。
Example 4
场景
同样,如果我们将目录结构更改为以下形式会怎样呢?
|
|
父POM如何指定它的模块?
解决方案
与之前差不多,指定模块的路径:
|
|
项目继承 VS 项目聚合
如果有几个Maven项目,并且他们都有相似的配置,那么可以通过提取这些相似的配置并创建父项目来重构项目。因此,需要做的是让Maven项目继承父项目,然后这些配置将适用于所有项目。
如果有一组一起构建或处理的项目,可以创建一个父项目,并声明这些项目是父项目的模块。通过这样,我们只需要构建父类,其他的会随之构建好。
当然,我们可以同时拥有项目继承和聚合。这意味着,可以让模块们指定一个父项目;同时,让该父项目指定那些项目为它的模块。需要遵循如下三条规则:
- 在每个子POM中指定它们的父POM是谁
- 将父pom的打包类型更改为值“pom”
- 在父POM中指定其模块的目录
Example 5
场景
依旧使用上面的POM:
com.mycompany.app:my-app:1的POM
|
|
com.mycompany.app:my-module:1的POM
|
|
目录结构如下:
|
|
解决方案
同时进行项目继承和聚合
com.mycompany.app:my-app:1的POM
|
|
com.mycompany.app:my-module:1的POM
|
|
注意:Profile的继承与用于POM本身的继承策略相同。
项目插值和变量
Maven鼓励的实践之一是不要重复自己的操作。但是,在某些情况下,您需要在几个不同的位置使用相同的值。为了帮助确保值只指定一次,Maven允许在POM中使用自己的变量和预定义的变量。
例如,访问project.version
变量,可以这样引用:
|
|
需要注意的一个因素是,这些变量是在继承之后处理的。这意味着,如果父项目使用变量,那么最终使用的将是它在子项目中的定义,而不是父项目中的定义。
可用变量
项目模型变量
模型中单个值元素的任何字段都可以作为变量引用。例如,${project.groupId}
,${project.version}
,${project.build.sourceDirectory}
等。参阅POM引用以查看完整的属性列表。
特殊变量
属性 | 解释 |
---|---|
project.basedir | 当前项目所在目录 |
project.baseUri | 当前项目所在目录,表示为URI。>=Maven2.1 |
maven.build.timestamp | 表示构建开始的时间戳。>=Maven2.1.0-M1 |
构建时间戳的格式可以通过声明property maven.build.timestamp
来定制。格式如下:
|
|
属性
可以将任何属性定义为变量,考虑如下的例子:
|
|