Maven學習筆記三【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 - 專案的版本號
示例:
<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-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。
<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的父專案,修改com.mycompany.app:my-module:1’的pom.xml如下:
<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或version與父模組相同,可以刪除模組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>
Example 2
場景
儘管如果父專案已經安裝到本地儲存庫中,或者在特定的目錄結構中(模組的目錄為父POM的子目錄),上面的配置方式是可行的。但是如果父專案還沒安裝,並且目錄結構與下面的示例一樣,該怎麼辦呢?
. |-- my-module |`-- pom.xml `-- parent `-- pom.xml
解決方案
要處理這個目錄結構,需要將<relativePath>
標籤新增到parent部分:
<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.xml對於父pom.xml的相對路徑。
專案聚合
專案聚合類似於專案繼承。但它不是從模組指定父POM,而是從父POM指定模組。通過這樣,父專案知道了它的模組,如果對父專案呼叫Maven命令,那麼命令也會執行到父專案的各個模組。要進行專案聚合,需要做如下:
- 將父專案的打包型別改為pom
- 在父POM中指定模組
Example 3
場景
沿用上面的POM和目錄結構:
com.mycompany.app:my-app:1的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的POM
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-module</artifactId> <version>1</version> </projec
目錄結構如下:
. |-- 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>
如上,增加了<packaging>
和<modules>
部分。現在,每當Maven命令處理com.mycompany.app:my-app:1時,相同的命令會在com.mycompany.app:my-module:1 上執行。另外,一些命令以不同的方式處理命令聚合。
Example 4
場景
同樣,如果我們將目錄結構更改為以下形式會怎樣呢?
. |-- my-module |`-- pom.xml `-- parent `-- pom.xml
父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>
專案繼承 VS 專案聚合
如果有幾個Maven專案,並且他們都有相似的配置,那麼可以通過提取這些相似的配置並建立父專案來重構專案。因此,需要做的是讓Maven專案繼承父專案,然後這些配置將適用於所有專案。
如果有一組一起構建或處理的專案,可以建立一個父專案,並宣告這些專案是父專案的模組。通過這樣,我們只需要構建父類,其他的會隨之構建好。
當然,我們可以同時擁有專案繼承和聚合。這意味著,可以讓模組們指定一個父專案;同時,讓該父專案指定那些專案為它的模組。需要遵循如下三條規則:
- 在每個子POM中指定它們的父POM是誰
- 將父pom的打包型別更改為值“pom”
- 在父POM中指定其模組的目錄
Example 5
場景
依舊使用上面的POM:
com.mycompany.app:my-app:1的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的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的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的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>
注意:Profile的繼承與用於POM本身的繼承策略相同。
專案插值和變數
Maven鼓勵的實踐之一是不要重複自己的操作。但是,在某些情況下,您需要在幾個不同的位置使用相同的值。為了幫助確保值只指定一次,Maven允許在POM中使用自己的變數和預定義的變數。
例如,訪問project.version
變數,可以這樣引用:
<version>${project.version}</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
來定製。格式如下:
<project> ... <properties> <maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format> </properties> ... </project>
屬性
可以將任何屬性定義為變數,考慮如下的例子:
<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>