《Maven官方文件》POM檔案
什麼是POM?
POM(project object model)包含了工程資訊和工程的配置細節,Maven使用POM檔案來構建工程。POM檔案包含了工程中的大部分預設值。舉個例子,target是預設的構建目錄,src/main/java是預設的原始碼目錄,src/test/java是預設的測試原始碼目錄,等等。
Maven2中的pom.xml就是Maven1中的project.xml。相比於在maven.xml中包含可執行的goal,現在goals和plugins都可以在pom.xml中配置。當執行一個task或者goal時,Maven會在當前目錄下尋找並讀取pom.xml來獲取配置資訊,然後執行goal。
能在pom.xml中宣告的配置包括工程依賴(project dependencies),外掛(plugins),可執行的目標(goals),構建配置(build profiles)等等。其他資訊,比如工程版本,描述,開發者,郵件列表等等也可以在pox.xml中宣告。
Super POM
Super POM是Maven的預設POM檔案,除非你顯示的宣告繼承關係,否則所有的POM檔案都是在Super POM的基礎上的擴充套件,也就是說,Super POM中的的配置會被你的工程中建立的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>
最小化POM
一個最小化的POM檔案的要求如下:
- project 標籤作為頂層標籤
- modelVersion – 應該設為4.0.0
- groupId – 工程開發組的唯一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″。
如第一節所說,如果配置細節沒有顯示的設定,Maven將會使用繼承自Super POM預設配置。其中一個預設值就是包的型別(packaging type),每個Maven工程都有一個包型別,如果沒有在POM中設定,則預設為”jar”。
前面的Minimal POM中,其中 repositories 這個值沒有設定,如果你使用minimal POM來構建你的工程,它將使用繼承Super POM中的 repositories 值(http://repo.maven.apache.org/maven2),當Maven在POM中找到依賴,它就會去這個地址下載依賴包。
工程繼承
POM中可配置的元素如下:
- 依賴 (dependencies)
- 開發者和貢獻者 (developers and contributors)
- 外掛列表,包括報告 (plugin lists, including reports)
- 相應id的外掛執行 (plugin executions with matching ids)
- 外掛配置 (plugin configuration)
- 資源 (resources)
Super POM就是一個工程繼承的例子。你也可以通過在POM中指定parent element來引入你自己的POM作為基礎。就像下面的例子:
Example 1
情景
在這個例子中,我們還是沿用com.mycompany.app:my-app:1這個名稱。現在讓我們引入另一個工件,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 是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的父工件(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結點,這個結點允許我們指定當前POM的父POM。通過指定父POM的完整名稱(即groupId,artifactId,version這三個標籤),我們的模組(module)就能夠繼承父POM中的屬性了。
另外,如果我們希望groupId和模組的version和他們的parents相同,你可以移除當前模組POM中的groupId和version標籤。
<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>
這樣做可以讓當前模組整合父POM的groupid和version。
Example 2
情景
在父工程已經安裝在本地倉庫或指定目錄結構(父POM是模組POM的上一級目錄)中時,這樣做是可以得。
但是如果父工程沒有安裝或者是像這樣的目錄機構呢?
. |-- my-module | `-- pom.xml `-- parent `-- pom.xml
解決方案
為了修正這個目錄結構,我們將在parent結點中新增<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的相對路徑。
工程聚合
工程聚合和工程繼承很相似,但不是從子模組指定父POM,而是從父POM指定子模組。這樣做的話,父工程就知道子模組的存在了,而且如果Maven命令從父工程呼叫,在子模組中也能順利執行。工程聚合要求如下做法:
- 將父POM的packageing屬性設為”pom”
- 在父POM中指定模組的目錄(子POM)
Example 3
情景
還是上次的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>
directory structure
. |-- my-module | `-- pom.xml `-- pom.xml
解決方案
如果我們準備將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>
在修改後的POM中,增加了packaging部分和模組部分,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中執行時,同樣的明明也會在com.mycompany.app:my-module:1中執行。此外,有些命令(goals soecifically)以不同的方式處理工程聚合的情況。
Example 4
情景
如果我們將目錄結構改成這樣
. |-- 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>
工程繼承與工程聚合
如果你有好幾個Maven 工程,並且這些工程有著相似的配置,你可以通過將相同的配置放到一個父工程中來重構。這樣的話,你所要做的就是讓你的Maven工程繼承這個父工程,這些配置就能在所有的工程中通用了。
如果你有一組工程一起構建和執行,你可以建立一個父工程,並在父工程中宣告這些工程為它的模組,這樣做,你只要構建父工程,子工程也會隨之構建。
當然,你可以同時做工程繼承和工程聚合。這意味著,你可以為你的所有模組指定一個父工程,同時,父工程中可以指定其餘的Maven工程為它的子模組。你只需要應用這三條規則:
- 在所有子POM中指定它們的父POM。
- 將父POM的packaging元素的值設為”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>
目錄結構
. |-- my-module | `-- pom.xml `-- parent `-- pom.xml
解決方案
同時做工程繼承和工程聚合,你只要應用三條法則。
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繼承的策略相同
工程改寫和變數
Maven鼓勵的做法是不要做重複的工作(don’t repeat yourself)。但總有在不同的地方使用相同屬性的情況。為了確保屬性值指定一次,Maven允許你在POM使用你自己的變數或者預先定義的變數。
舉個例子,為了使用project.version這個變數,你可以這樣引用:
<version>${project.version}</version>
要注意的是這些變數在繼承之後才會被處理。這意味著如果一個父工程使用了一個變數,它們在子工程中的定義與在父工程中的定義會不一樣,是最後使用的那個。
可用的變數
工程模型變數
一個Model的任何欄位都是一個單獨的可以做為變數引用的值元素。例如,${project.groupId}, ${project.version},${project.build.sourceDirectory} 等等。參考POM reference 列舉的全部屬性。這些變數都用”project”字首來引用。你可以看看pom references. 作為字首,或者完全省略字首 – 這些形式現在已經廢棄不再使用了。
特殊變數
project.basedir | 當前工程所在的目錄 |
project.baseUri | 當前工程所在的目錄,表示為一個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>
格式化模式必須遵守API文件中給出的規則。如果這個屬性不存在,預設值就是示例中給出的值
屬性
你同樣可以將任何在工程中定義的屬性作為變數引用,看看下面的例子:
<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>