Apache Maven之pom.xml
什么是POM?
- Project Object Model或者POM是Maven项目(project)的基本工作单元。它是一个
XML
文件,其中包含此项目的项目信息以及用Maven构建此项目的配置详情信息。它包含了大多数项目的默认值。例如说target
是构建文件目录;src/main/java
是源文件目录;src/test/java
是测试源文件目录等等。 - POM(Project Object Model)是从Maven 1中的
project.xml
重命名为Maven 2中的pom.xml
。现在,在pom.xml
中配置目标或者插件,而不是拥有包含可执行目标的maven.xml
文件。当执行一个任务或者目标时,Maven会查找当前目录下面的POM文件(也就是pom.xml
文件)。Maven去阅读这个POM文件(也就是pom.xml
文件),从中获取所需的配置信息,然后执行目标。 - 可以在POM文件中指定的一些配置是项目依赖项、可执行的插件或者目标、构建配置文件等等。还可以指定其他的信息,比如项目版本号、项目描述、项目开发人员、项目邮件列表等等。
Super POM
- Super POM文件是Maven的默认POM文件。除非明确地进行设置,否则所有的POM文件都会继承
Super POM
文件。这就意味着Super POM文件中指定的配置将由您为项目创建的POM文件继承。下面的代码片段是Maven 2.0.x的Super POM。
<project>
<modelVersion>4.0.0</modelVersion>
<name>Maven Default Project</name>
<repositories>
<repository>
<id>central</id>
<name>Maven Repository Switchboard</name>
<layout>default</layout>
<url>http://repo1.maven.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Maven Plugin Repository</name>
<url>http://repo1.maven.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>
<build>
<directory>target</directory>
<outputDirectory>target/classes</outputDirectory>
<finalName>${artifactId}-${version}</finalName>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
</build>
<reporting>
<outputDirectory>target/site</outputDirectory>
</reporting>
<profiles>
<profile>
<id>release-profile</id>
<activation>
<property>
<name>performRelease</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
- 下面的代码片段是Maven 2.1.x的Super DOM。
<project>
<modelVersion>4.0.0</modelVersion>
<name>Maven Default Project</name>
<repositories>
<repository>
<id>central</id>
<name>Maven Repository Switchboard</name>
<layout>default</layout>
<url>http://repo1.maven.org/maven2</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Maven Plugin Repository</name>
<url>http://repo1.maven.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>
<!-- TODO: MNG-3731 maven-plugin-tools-api < 2.4.4 expect this to be relative... -->
<scriptSourceDirectory>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>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.0</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.3.1</version>
</plugin>
<plugin>
<artifactId>maven-ejb-plugin</artifactId>
<version>2.1</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<artifactId>maven-plugin-plugin</artifactId>
<version>2.4.3</version>
</plugin>
<plugin>
<artifactId>maven-rar-plugin</artifactId>
<version>2.2</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.0-beta-8</version>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.3</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>2.0-beta-7</version>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.0.4</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.4.3</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-alpha-2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<outputDirectory>${project.build.directory}/site</outputDirectory>
</reporting>
<profiles>
<profile>
<id>release-profile</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
最低要求的POM(Minimum POM)
- POM文件的最低要求如下:
- 项目根目录;
- modelVersion - 应设置为4.0.0;
- groupId - 项目组的ID;
- artifactId - 工件的id(项目);
- version - 指定组下的工件的版本;
- 这里有一个实例:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
- 一个POM文件要求配置其中的
groupId
,artifactId
和版本(version
)。这三个值构成项目的完全限定工件名称。在POM文件中的形式是<groupId>:<artifactId>:<version>
,就好像上面实例给出的那样,它的完全限定工件名称是"com.mycompany.app:my-app:1"
。 - 此外,如第一部分所述,如果未指定配置详细信息,Maven将使用其默认值进行配置。其中一个默认值是包装(
packaging
)类型,每一个Maven项目中都有一个包装(packaging
)类型。如果未在POM文件中进行指定,则使用默认值"jar"
。 - 此外,正如您所看到的,在最小的POM配置文件中,并没有指定存储库(
repositories
)。如果使用最小的POM配置文件去构建您的项目程序,它将继承Super POM
中的存储库(repositories
)配置。因此,当Maven在最小的POM中看到依赖关系时,它会知道这些依赖关系将从Super POM
中指定的http://repo.maven.apache.org/maven2下载。
Project Inheritance(项目继承)
- POM配置文件中合并的元素有以下这些:
- 依赖关系(
dependencies
); - 开发者以及贡献者(
developers and contributes
); - 插件列表(包括报告)(
plugins lists(including reports)
); - 插件配置文件(
plugin configuration
); - 资源(
resources
);
- 依赖关系(
Super DOM
配置文件是项目继承中的一个实例,但是您也可以通过在POM中指定父元素来引入您自己的父POM配置文件,如以下示例所示。
示例1(Example 1)
- 情景(The scenario)
- 例如, 让我们去复用我们自己在前面设置的工件(artifact),
com.mycompany.app:my-app:1
。并且让我们去介绍另外一个工件(artifact),com.mycompany.app:my-module:1
。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
- 让我们指定他们的目录结构如下:
.
|-- my-module
| `-- pom.xml
`-- pom.xml
注意:
my-module/pom.xml
的POM配置文件是关于com.mycompany.app:my-module:1
,与此同时,pom.xml
的POM配置文件是关于com.mycompany.app:my-app:1
。
- 解决方案(The Solution)
- 现如今,如果我们将
com.mycompany.app:my-app:1
转换为com.mycompany.app:my-module:1
的父工件,我们不得不去修改com.mycompany.app:my-module:1
的POM配置文件为如下所示: com.mycompany.app:my-module:1
的POM配置文件
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
- 请注意,我们现在有一个添加部分,即父部分。本节允许我们指定哪个工件(artifact)是POM的父母(parent)项。我们通过制定父母POM配置文件的完全限定工件名称来实现。通过此设置,我们的模块现在可以继承父母POM配置文件的一些属性。
- 或者,如果我们希望
groupId
和/或模块的版本与其父母模块相同,则可以在其POM中删除groupId
和/或模块的版本标识。
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
- 这允许模块继承
groupId
和/或其父母POM配置文件的版本。
示例2(Example 2)
- 情景(The Scenario)
- 但是,如果父母项目已经安装在我们的本地存储中或者在特定的目录结构中(父母
pom.xml
是一个高于模块pom.xml
的目录),那么这将起作用。 - 但是,如果尚未安装父母项目并且目录结构如下所示:
.
|-- my-module
| `-- pom.xml
`-- parent
`--pom.xml
- 解决方案(The Solution)
- 要解决此目录结构(或者任何其他目录结构),我们必须将
<relativePath>
元素添加到父母节点。
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
- 顾名思义,它是从模块的(module’s)
pom.xml
到父母的(parent’s)pom.xml
的相对路径。
Project Aggregation(项目聚合)
- 项目聚合(Project Aggregation)类似于项目继承(Project Inheritance)。但是它不是从模块中指定父母POM配置文件,而是从父母POM配置文件指定模块。通过这样做,父母项目现在知道它的模块,并且如果针对父母项目调用Maven命令,那么Maven命令也将执行到父母模块。要执行项目聚合(Project Aggregation),您必须执行一下操作:
- 将父母POM配置文件包装(POMs packaging)更改为
"pom"
; - 在父母POM配置文件中指定其模块的目录(子POM配置文件);
- 将父母POM配置文件包装(POMs packaging)更改为
示例3(Example 3)
- 情景(The Scenario)
- 鉴于之前的原有工件(artifact)POMs,以及文件目录结构
com.mycompany.app:my-app:1's POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groudId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
com.mycompany.app:my-module:1's POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
directory structure
`
|-- my-module
| `-- pom.xml
`-- pom.xml
- 解决方案(The Solution)
- 如果我们将
my-module
聚合到my-app
中,我们只需要去修改my-app
就可以了。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>my-module</module>
</modules>
</project>
- 包装部分(
the packaging
)和模块部分(the modules
)都被添加在修订后的com.mycompany.app:my-app:1
中。对于打包(packaging
)来说,其值被设置为"pom"
,对于模块部分来说,我们拥有<module>my-module</module>
这样的标签元素。<module>
标签元素的值是从com.mycompany.app:my-app:1
到com.mycompany.app:my-module:1
的POM配置文件的相对路径。(通过实践之后,我们使用模块中的artifactId
作为模块目录的名称)。 - 现在,每当一个Maven命令在处理
com.mycompany.app:my-app:1
,同样的Maven命令也将针对com.mycompany.app:my-module:1
进行运行。此外,一些命令(特定目标)以不同的方式处理项目聚合。
示例4(Example 4)
- 情景
- 但是如果我们将目录结构更改为如下所示:
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
父母的pom配置文件将如标明它的模块?
解决方案
- 答案就是等同于示例3(Example3)的方式,通过标明路径到模块里面(the module)。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app<groupId>
<artifactId>my-app<artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>../my-module</module>
</modules>
</project>
Project Inheritance vs Project Aggregation(项目继承对比于项目聚合)
- 如果您有几个
Maven
项目,并且它们都有类似的配置,你可以通过拉出那些类似的配置并创建一个父母项目来重构你的项目。因此,您所要做的就是让您的Maven项目继承该父母项目,然后将这些配置应用于所有的这些项目之中。 - 如果您有一组一起构建或者处理的项目,则可以创建父母项目并且让该父母项目将这些项目声明为其模块。通过这样做,您只需要建立父母项目,其余的将遵循。
- 当然, 您也可以同时拥有
Project Inheritance
和Project Aggregation
。这就意味着,您可以让您的模块指定父母项目,同时让该父母项目将这些Maven项目指定为其模块。您只需要应用所有三个规则:
- 在每个子POM配置文件中指定其父母POM配置文件是谁。
- 将父母POM配置文件包装(
packaging
)更改为值"pom"
。 - 在父母POM中指定其模块的目录(子POM文件)。
示例5(Example 5)
- 情景
- 再一次鉴于之前的原工件(
artifact
)POMs,com.mycompany.app:my-app:1's POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
com.mycompany.app:my-module:1's POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
- 并且这个目录结构
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
- 解决方案
- 结合项目继承(project inheritance)以及项目聚合(project aggregation),您仅仅只需要遵守下面的三条的规则。
com.mycompany.app:my-app:1's POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>../my-module</module>
</modules>
</project>
com.mycompany.app:my-module:1's POM
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relationPath>../parent/pom.xml</relationPath>
</parent>
<modelVersion>4.0.0<modelVersion>
<artifactId>my-module</artifactId>
</project>
注意: Profile继承与POM配置文件本身使用的继承策略相同。
Project Interpolation and Variables
- Maven鼓励的一种做法是不要重复自己。 但是,在某些情况下,您需要在几个不同的位置使用相同的值。 为了帮助确保仅指定一次值,Maven允许您在POM中使用自己的和预定义的变量。
- 例如,要访问
project.version
变量,您可以像这样引用它:
<version>${project.version}</version>
- 需要注意的一个因素是,综上所述,这些变量在继承之后进行处理。 这意味着如果父项目使用变量,那么它在子项中的定义(而不是父项)将是最终使用的定义。
可利用的变量值
- Project Model Variables
- 作为单个值元素的任何字段都可以作为变量引用。例如,
${project.groupId}
,${project.version}
,${project.build.sourceDirectory}
等等。请参阅POM配置文件参考以查看完整的属性列表。 这些变量都是由前缀
"project"
引用。你也可以看到pom
的引用。作为前缀或者完全省略前缀——这些表单现在已经弃用,不应该使用。Special Variables
project.basedir |
当前项目所在的目录 |
---|---|
project.baseUrl |
当前项目所在的目录, 表示为URI。从Maven 2.1.0开始 |
maven.build.timestamp |
表示构建开始的时间戳。从Maven 2.1.0-M1开始 |
- 可以通过声明属性
maven.build.timestamp.format
来自定义构建时间戳的格式,如下例所示:
<project>
...
<properties>
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format>
</properties>
...
</project>
格式模式必须符合
SimpleDateFormat
的API文档中给出的规则。 如果该属性不存在,则格式默认为示例中已给出的值。Properties
- 您还可以将项目中定义的任何属性作为变量引用。 请考虑以下示例:
<project>
...
<properties>
<mavenVersion>2.1</mavenVersion>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<version>${mavenVersion}</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>${mavenVersion}</version>
</dependency>
</dependencies>
...
</project>
JackDan Thinking
What_is_a_POM