原英文文檔地址:Introduction to the POM
1. 什么是POM?
POM(project object model)包含了工程信息和工程的配置細(xì)節(jié),Maven使用POM文件來構(gòu)建工程。POM文件包含了工程中的大部分默認(rèn)值。舉個例子,target是默認(rèn)的構(gòu)建目錄,src/main/java是默認(rèn)的源碼目錄,src/test/java是默認(rèn)的測試源碼目錄,等等。
Maven2中的pom.xml就是Maven1中的project.xml。相比于在maven.xml中包含可執(zhí)行的goal,現(xiàn)在goals和plugins都可以在pom.xml中配置。當(dāng)執(zhí)行一個task或者goal時,Maven會在當(dāng)前目錄下尋找并讀取pom.xml來獲取配置信息,然后執(zhí)行g(shù)oal。
能在pom.xml中聲明的配置包括工程依賴(project dependencies),插件(plugins),可執(zhí)行的目標(biāo)(goals),構(gòu)建配置(build profiles)等等。其他信息,比如工程版本,描述,開發(fā)者,郵件列表等等也可以在pox.xml中聲明。
2. Super POM
Super POM是Maven的默認(rèn)POM文件,除非你顯示的聲明繼承關(guān)系,否則所有的POM文件都是在Super POM的基礎(chǔ)上的擴(kuò)展,也就是說,Super POM中的的配置會被你的工程中創(chuàng)建的pom.xml繼承。
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 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>${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>
3. 最小化POM
一個最小化的POM文件的要求如下:
- project 標(biāo)簽作為頂層標(biāo)簽
- modelVersion – 應(yīng)該設(shè)為4.0.0
- groupId – 工程開發(fā)組的唯一id
- artifactId – 工件(artifact)或工程(projrct)的唯一id
- version – 版本號
這里是一個最小化POM的例子:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
說明:
- 在POM文件中需要聲明 groupId , artifactId 和 version 。這三個值以<groupId>:<artifactId>:<version>的形式聲明,它們組成了工程的完整名稱。比如上面的例子,完整名稱為”com.mycompany.app:my-app1″。
- 如第一節(jié)所說,如果配置細(xì)節(jié)沒有顯示的設(shè)置,Maven將會使用繼承自Super POM默認(rèn)配置。其中一個默認(rèn)值就是包的類型(packaging type),每個Maven工程都有一個包類型,如果沒有在POM中設(shè)置,則默認(rèn)為”jar”。
- 前面的Minimal POM中,其中 repositories 這個值沒有設(shè)置,如果你使用minimal POM來構(gòu)建你的工程,它將使用繼承Super POM中的 repositories 值(http://repo.maven.apache.org/maven2),當(dāng)Maven在POM中找到依賴,它就會去這個地址下載依賴包。
4. 工程繼承
POM中可配置的元素如下:
- 依賴 (dependencies)
- 開發(fā)者和貢獻(xiàn)者 (developers and contributors)
- 插件列表,包括報告 (plugin lists, including reports)
- 相應(yīng)id的插件執(zhí)行 (plugin executions with matching ids)
- 插件配置 (plugin configuration)
- 資源 (resources)
Super POM就是一個工程繼承的例子。你也可以通過在POM中指定parent element來引入你自己的POM作為基礎(chǔ)。就像下面的例子:
Example 1
情景
在這個例子中,我們還是沿用com.mycompany.app:my-app:1這個名稱。現(xiàn)在讓我們引入另一個工件,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>
指定它們的目錄結(jié)構(gòu)如下:
.
|-- my-module
| `-- pom.xml
`-- pom.xml
注意: my-module/pom.xml
是com.mycompany.app:my-module:1
的POM文件,而 pom.xml
是com.mycompany.app:my-app:1
的POM文件。
解決方案:現(xiàn)在,如果我們將com.mycompany.app:my-app:1
指定為com.mycompany.app:my-module:1
的父工件(parent artifact),我們需要修改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>
注意: 我們需要添加一個parent結(jié)點(diǎn),這個結(jié)點(diǎn)允許我們指定當(dāng)前POM的父POM。通過指定父POM的完整名稱(即groupId,artifactId,version這三個標(biāo)簽),我們的模塊(module)就能夠繼承父POM中的屬性了。
另外,如果我們希望groupId和模塊的version和他們的parents相同,你可以移除當(dāng)前模塊POM中的groupId和version標(biāo)簽。
<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>
這樣做可以讓當(dāng)前模塊集成父POM的groupid和version。
Example 2
情景
在父工程已經(jīng)安裝在本地倉庫或指定目錄結(jié)構(gòu)(父POM是模塊POM的上一級目錄)中時,這樣做是可以得。
但是如果父工程沒有安裝或者是像這樣的目錄機(jī)構(gòu)呢?
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
解決方案:為了修正這個目錄結(jié)構(gòu),我們將在parent結(jié)點(diǎn)中添加<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>
顧名思義,這個元素指定了從模塊POM到其父POM的相對路徑。
5. 工程聚合
工程聚合和工程繼承很相似,但不是從子模塊指定父POM,而是從父POM指定子模塊。這樣做的話,父工程就知道子模塊的存在了,而且如果Maven命令從父工程調(diào)用,在子模塊中也能順利執(zhí)行。工程聚合要求如下做法:
- 將父POM的packageing屬性設(shè)為”pom”
- 在父POM中指定模塊的目錄(子POM)
Example 3
情景
還是上次的POM和目錄結(jié)構(gòu)
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>
directory structure
.
|-- my-module
| `-- pom.xml
`-- pom.xml
解決方案: 如果我們準(zhǔn)備將my-module聚合進(jìn)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>
在修改后的POM中,增加了packaging部分和模塊部分,packaging的值設(shè)為”pom”,模塊部分增加了<module>my-module</module>。<module>的值是com.mycompany.app:my-app:1到com.mycompany.app:my-module:1的POM的相對路徑(練習(xí)中,我們用模塊的artifactId作為目錄名稱)。
現(xiàn)在,當(dāng)Maven命令在com.mycompany.app:my-app:1中執(zhí)行時,同樣的明明也會在com.mycompany.app:my-module:1中執(zhí)行。此外,有些命令(goals soecifically)以不同的方式處理工程聚合的情況。
Example 4
情景
如果我們將目錄結(jié)構(gòu)改成這樣
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
父POM又該如何指定子模塊呢?
解決方案:答案是 – 跟Example 3一樣,指定路徑就好了。
<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>
6. 工程繼承與工程聚合
如果你有好幾個Maven 工程,并且這些工程有著相似的配置,你可以通過將相同的配置放到一個父工程中來重構(gòu)。這樣的話,你所要做的就是讓你的Maven工程繼承這個父工程,這些配置就能在所有的工程中通用了。
如果你有一組工程一起構(gòu)建和運(yùn)行,你可以創(chuàng)建一個父工程,并在父工程中聲明這些工程為它的模塊,這樣做,你只要構(gòu)建父工程,子工程也會隨之構(gòu)建。
當(dāng)然,你可以同時做工程繼承和工程聚合。這意味著,你可以為你的所有模塊指定一個父工程,同時,父工程中可以指定其余的Maven工程為它的子模塊。你只需要應(yīng)用這三條規(guī)則:
- 在所有子POM中指定它們的父POM。
- 將父POM的packaging元素的值設(shè)為”pom”。
- 在父POM中指定子模塊(子POM)的目錄。
Example 5
情景
還是上次的POM,
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>
目錄結(jié)構(gòu)
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
解決方案: 同時做工程繼承和工程聚合,你只要應(yīng)用三條法則。
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>
<relativePath>../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
注意:配置繼承的策略與POM繼承的策略相同
7. 工程改寫和變量
Maven鼓勵的做法是不要做重復(fù)的工作(don’t repeat yourself)。但總有在不同的地方使用相同屬性的情況。為了確保屬性值指定一次,Maven允許你在POM使用你自己的變量或者預(yù)先定義的變量。
舉個例子,為了使用 project.version
這個變量,你可以這樣引用:
<version>${project.version}</version>
要注意的是這些變量在繼承之后才會被處理。這意味著如果一個父工程使用了一個變量,它們在子工程中的定義與在父工程中的定義會不一樣,是最后使用的那個。
可用的變量
工程模型變量
一個Model的任何字段都是一個單獨(dú)的可以做為變量引用的值元素。例如, ${project.groupId}
, ${project.version}
, ${project.build.sourceDirectory}
等等。參考POM reference 列舉的全部屬性。這些變量都用 project.
前綴來引用。你可以看看pom.
參考,或者完全省略前綴 – 這些形式現(xiàn)在已經(jīng)廢棄不再使用了。
特殊變量
變量值 | 說明 |
---|---|
project.basedir | 當(dāng)前工程所在的目錄 |
project.baseUri | 當(dāng)前工程所在的目錄,表示為一個URI,Maven 2.1.0之后 |
maven.build.timestamp | 時間戳,表示開始構(gòu)建的時間,Maven 2.1.0-M1之后 |
構(gòu)建時間戳的格式可以在maven.build.timestamp.format屬性中自定義,示例如下:
<project>
...
<properties>
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format>
</properties>
...
</project>
格式化模式必須遵守API文檔中給出的規(guī)則。如果這個屬性不存在,默認(rèn)值就是示例中給出的值.
屬性
你同樣可以將任何在工程中定義的屬性作為變量引用,看看下面的例子:
<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>