1. 程式人生 > >Maven中的幾個重要概念(三):POM

Maven中的幾個重要概念(三):POM

原文:

http://maven.apache.org/guides/introduction/introduction-to-the-pom.html

本文基本上是翻譯+一點點理解。

  • 什麼是POM

POM(Project Object Model) 是Maven的基礎。它是一個XML檔案,包含了Maven用來build專案所需要的專案配置的資訊。

(譯者:在使用ant進行build時,我們需要通過script告訴ant每一步要做什麼,同時提供每一步需要的資訊。

例如,首先要編譯,編譯的原始碼在哪裡,目的碼放哪裡等等。

在Maven中我們不需要告訴Maven應該做些什麼,僅需要在pom中提供一些必要的資訊即可。對於那些在pom中沒有提到的資訊,Maven就會使用預設值。

例如Maven預設原始碼在src/main/java中。因此Maven在最大程度上簡化了專案build的過程。)

它包含了可用於大部分專案的預設值。例如,build directory預設使用<target>定義;source directory,預設使用了src/main/java;test source directory預設使用了src/main/test等等。

在Maven1中(Maven的早期版本)POM的名字是project.xml,而在Maven 2中改為pom.xml。

(譯者:通常認為Maven從1到2發生了根本性的改變,因此儘管可能你使用的Maven是3.x的版本,仍然會發現很多以m2命名的目錄。)


同時,以前在maven.xml中包含的goal,plugin等資訊現在也被放到了pom.xml中。當執行一個task或goal時,Maven搜尋當前目錄下的pom檔案,從其中取出需要的配置資訊並執行goal。

(譯者:plugin和goal的概念非常重要,請參考我的另外一篇介紹Maven中的lifecycle的文章。)

另外一些需要在POM中配置的資訊是project dependencies,也就是那些需要被執行的plugin或goal,build profile等等。其他專案相關資訊,包括專案版本,專案描述,開發人員列表,郵件列表等等也可以在POM中。

  • Super POM
Super POM是Maven的預設POM。所有的POM都繼承了super POM。也就是說,所有的POM中的資訊都來自於Super POM,但在子POM中的配置資訊會覆蓋Super POM中的重複項。

(譯者:文中分別寫出了Maven2.0.x和2.1.x的super POM的具體內容。這裡請參考原文)

  • 最簡單的pom.xml

一個最簡單的POM檔案需要包括的內容如下:

(譯者:也就是說,如果想建立一個簡單的Maven專案,提供一個如此簡單的POM就夠了。Maven會自動完成剩下的事情)

  • project root
  • modelVersion - should be set to 4.0.0
  • groupId - the id of the project's group.
  • artifactId - the id of the artifact (project)
  • version - the version of the artifact under the specified group
具體的例子:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
</project>

一個POM必須配置專案的groupId, artifactId, 和version。這三個值構成了專案的fully qualified artifact name。那就是<groupId>:<artifactId>:<version>。對於上面的例子,fully qualified artifact name就是“com.mycompany.app:my-app:1”

同時,正如在第一節提到的,如果一些配置資訊沒有被提供,Maven將會使用預設值。這些預設值之一是packaging type。如果POM中沒有配置它,將會使用預設值jar。

此外,如同你在最簡單的POM中看到的,這個POM並沒有配置所使用的repositories

(譯者:repository是Maven中的另外一個重要概念,不清楚的同學請參考我的另外一篇關於Maven中repository的文章。)

如果你使用這個POM來build你的專案,它將從Super POM繼承repository的配置。因此,當Maven發現需要下載POM中的dependency時,它會到Super POM中配置的預設repository,http://repo1.maven.org/maven2去下載。

  • Project Inheritance 專案繼承

(譯者:project inheritance 和下面要提到的project aggregation 是理解專案間POM父子關係的關鍵,必須理解。)

另外一些可包含在POM中的資訊是:

  • dependencies
  • developers and contributors
  • plugin lists (including reports)
  • plugin executions with matching ids
  • plugin configuration
  • resources

其實Super POM就是專案繼承的的一個例子。然而你同樣可以通過在POM中加入<parent>,來引入其他的父POM。

示例一:

在前面的例子中我們已經引入了“com.mycompany.app:my-app:1”這個專案,現在我們再引入另一個專案“com.mycompany.app:my-module:1”並以此為例,講述如何讓my-app成為my-module的父專案。

<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 指的是my-module這個專案的POM,而pom.xml指my-app的POM。

現在,我們把my-module的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。這個配置允許我們設定哪個專案(artifact)是當前專案的父專案。我們需要設定父POM的fully qualified artifact name。配置好之後,my-module的POM就可以從my-app的POM中繼承一些配置資訊了。

另外,如果我們希望my-module的groupId和/或version與父專案保持一致,我們甚至可以刪除my-module的POM中的groupId和/或version。

示例二:


然而上例是有侷限性的。只有當父專案已經安裝到local repository中,或者必須是特殊的檔案結構(父專案的pom.xml在子專案的pom.xml的父一級目錄裡)時,上例才工作。

(譯者:我工作的就是類似的父子專案。子專案依賴於父專案。每次修改了父專案的程式碼後,必須執行:

mvn install //將父專案編譯並加入到repository中

之後才能順利的執行子專案。)

如果父專案沒有安裝到local repository中,同時目錄結構如下(父子專案在平行的目錄結構中)就會有問題:

.
 |-- my-module
 |   `-- pom.xml
 `-- parent
     `-- pom.xml

為了解決這個目錄結構(也可以是其他目錄結構)導致的問題,我們必須在parent section中使用<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>

如同<relativePath>的字面意思(相對路徑),它是module的pom.xml到父pom.xml的相對路徑。

  • Project Aggregation 專案整合

project aggregation 和project inheritance類似。但與project inheritance在my-module中設定父POM不同的是,project aggregation是在父POM中設定my-module。

通過這種方式,父專案在知道它的子模組。同時,如果在父專案上執行Maven命令,父專案和所有的子模組都會執行該命令。

(譯者:這就是為什麼在Maven的POM中既有父子關係,又有子父關係。)

要使用project aggregation, 必須:

1, 將父POM的<packaging>改為“pom”。

2, 在父POM中設定子模組的路徑。

示例三:

再次使用之前的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
 `-- pom.xml

如果我們想把my-module加到my-app中,可以簡單的講my-app的pom.xml改為如下:

<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>和<modules>。前者的值被設定為“pom”,後者設定為<module>my-module</module>

<module>的值是從com.mycompany.app:my-app:1的pom到com.mycompany.app:my-module:1的pom的相對路徑(在例子中使用module的artifactId,即my-module作為目錄名,所以<module>設定的不是module名,而是目錄的名字)。

現在,對於my-app執行的任何一個Maven命令(或者說phase或goal),同時也會在my-module上執行。

示例四:

但是如果我們將目錄改為:

.
 |-- 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>

答案是,使用和例項三同樣的方法,將路徑加到<module>中。

  • Project Inheritance和Project aggregation的使用

如果你有好幾個Maven專案,同時它們有著類似的配置資訊,你可以重構你的這些專案,通過將這些相同的配置抽取出來,放到一個父專案中去。

這樣,你需要做的所有事情就是讓你的Maven專案繼承父專案,然後這些共同的配置就會生效了。

同時,如果你有一組專案,它們需要在一起build和process,你可以建立一個父專案,同時將這些子專案配置成父專案的modules。通過這種方式,你只需要build父專案而子專案就都會build了。

(譯者:例如我工作的專案,多個專案,比如專案A,B,C共享同樣的核心程式碼。採取的方式就是將核心程式碼抽取出來做成一個父專案稱為core,將)這些專案配置為父專案的modules。

可以通過build core專案,就build了所有的modules。

但有時也需要變通一下:當執行比如A專案的daily build時,我們並不需要build所有的專案。這時的做法就是,對於core專案,實際有4個pom檔案:

pom.xml, A_pom.xml, B_pom.xml, C_pom.xml。當執行A的daily build時,實際在build環境中使用的是A_pom.xml。同時該pom檔案中,core的子模組只有A一個。

另外需要注意的一點是:如何build的問題

例如我前面提到的我工作的專案,如果修改了core中的程式碼,並想重新build專案A時,有三種方法。

1,在core專案上執行mvn build。這樣core, A, B, C4個專案都會被build。

2,如果只想build專案A,就用A_pom.xml覆蓋core的pom檔案,然後執行mvn build。則會build專案core和A。

3,或者,對core專案執行mvn install(該命令會編譯,build並將build出來的jar包安裝到repository中去), 之後再在A專案執行mvn build)

但是,當然了,你也可以同時使用專案整合和專案繼承。意思是,你可以在子專案的pom中配置parent,同時在父專案中配置modules。你只需要明確下面3個規則:

1, 在每一個子專案pom中都要配置parent。

2,將父專案pom的packaging改為“pom”。

3,在父pom中配置子modules。

(譯者:到此專案間的關係已經講完了,讓我們來總結一下:

當我們拿到了幾個相關專案時,一定要先搞清楚這些專案間的父子關係。我們不僅要考察每一個專案的pom檔案,弄清楚他們之間的整合和繼承關係,也需要留意專案的目錄結構,以防止有些設定並沒有生效。

只有弄清楚了專案的關係,我們才能正確的使用Maven的功能)

(譯者:原文中還有一個示例五,是關於將上面3點都融合在一起的pom檔案,我覺得沒有必要再累述了。)

(另外需要說明的一點,如果開啟本地的repository,你會發現每個artifact(通常是jar包)也有自己的pom檔案。其實原因很簡單:Maven也要管理這些artifact。比如類庫A,同時也依賴於類庫B,C。

因此repository中的artifact也需要pom檔案來說明它們之間的關係)

  • 專案的插入值和變數

Maven鼓勵的一種做法是,不要自我重複。然而,有時候還是需要在幾個不同的地方使用相同值。為了保證僅在唯一的地方定義值,Maven允許你在pom中使用你自己定義的變數。

例如,為了在pom幾個不同的地方使用相同的值,project.version,你可以這樣做:

<version>${project.version}</version>

同時,在pom檔案中定義:

<project>
  ...
  <properties>
    <version>1.0.4</version>
  </properties>
  ...
</project>

需要注意的是,這些變數是在繼承機制生效後賦值的。這意味著,如果一個父專案pom包含變數,這些變數會被子專案繼承並可以在子專案中直接使用。

這裡有三種可使用的變數:

Project Model Variables

所有在pom中的獨立的element都可以作為一個變數。例如${project.groupId},${project.version},${project.build.sourceDirectory} 等等。參考POM reference來得到所有的properties。

所有這些變數使用時都應加上字首"project."。你也可能看到一些以“pom.”為字首的情況,但是已經不贊成這麼做了。

Special Variables
basedir The directory that the current project resides in.
project.baseUri The directory that the current project resides in, represented as an URI.Since Maven 2.1.0
maven.build.timestamp The timestamp that denotes the start of the build. Since Maven 2.1.0-M1

對於build timestamp的格式問題,可以通過<maven.build.timestamp.format>指定,如下:

<project>
  ...
  <properties>
    <maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
  </properties>
  ...
</project>

日期格式需要遵守的規則可以參考 SimpleDateFormat(java的)的API文件。如果沒有設定這個值,則使用上例中的預設值。

最後一種就是前面提到的<properties>,不累述。

原文到此結束,但我還想加一點關於POM中的dependency的內容。

dependency描述了當前專案對其他專案的依賴關係。如下例,表示當前專案依賴於log4j artifact(並非父子關係)。

    <dependencies>
       <dependency>
       <groupId>log4j</groupId>
       <artifactId>log4j</artifactId>
       <version>1.2.14</version>
       </dependency>

    </dependencies>

同樣我們使用的很多第三方工具,如JUnit等等,都需要使用dependency加入到專案的POM中(當然也可以使用專案繼承的方法,從父專案繼承)。

在eclipse中使用Maven外掛時,可以使用圖形化介面新增dependency。過程是:

1,點選新增dependency。

2,輸入名字,如JUnit。此時Maven外掛會到使用的remote repository中搜索相應的類庫。

3,搜尋到以後,點選希望新增的artifact,確定。此時POM檔案已經被修改了,加入了新增的dependency。

4,點選儲存。這時Maven就會開始從remote repository下載artifact。

如果沒有按照Maven外掛,另外一種方法就是直接修改pom.xml,加入dependency部分。儲存後Maven即開始下載artifact。

不過這裡有一個問題,直接修改pom.xml時,往往不知道要新增的類庫的完整名稱,即<groupId>:<artifactId>:<version>,進而也不知道該怎麼填寫<groupId><version>等內容。

這裡有一個方法,下面的網站是browse repository的:

使用方法類似:搜尋後,找到想要的類庫,然後就能看到對應的 <dependency>的內容。直接將該段xml複製到自己的pom.xml中就可以了。

完畢~~~

關於POM,可以參考http://maven.apache.org/pom.html 得到更詳細的解釋。

看完了Maven中的幾個重要概念一,二和三,相信對Maven已經有比較全面的瞭解了。

這個時候開始看Maven的完全參考手冊就會非常輕鬆了。

相關推薦

Maven重要概念():POM

原文: http://maven.apache.org/guides/introduction/introduction-to-the-pom.html 本文基本上是翻譯+一點點理解。 什麼是POMPOM(Project Object Model) 是Maven的基礎。它

)(1) Z-Stack協議重要概念的理解

     PANID的出現一般是伴隨在,確定通道以後的。PANID其全稱是Personal Area Network ID,網路的ID(即網路識別符號),是針對一個或多個應用的網路,用於區分不同的ZigBee網路,一般是mesh或者cluster tree兩種拓撲結構之一。所有節點的panID唯一,一個網路

Maven重要概念(二):lifecycle, phase and goal

原文:http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html 當我們在使用Maven做一些工作,如打包,編譯,執行測試等等任務時,我們已經使用到了Maven中的幾個重要概

App效能測試重要概念

我們在使用各種 App 的時候基本會關注到:這款軟體挺耗流量的?執行起來裝置掉電有點快嘛?切換頁面的時候還會有卡頓等現象?如果遇到有這些問題的 App 我們基本會將它請出我們的 我們在使用各種 App 的時候基本會關注到:這款軟體挺耗流量的?執行起來裝置掉電有點快嘛?切換頁面的時候還會有卡頓等現

OSPF概念

虛鏈路 net ospf -1 路由器 rtu 網絡 概念 link OSPF的有以下幾種LSA: Type-1 lsa (router isa) Type-2 lsa (network lsa) Type-3 lsa (network summary lsa) Type

MyBatis的重要概念和工作流程

.com 信息 獲得 sql 語句 進行 對象 結點 增刪改 build MyBatis 幾個重要的概念 Mapper 配置: Mapper 配置可以使用基於 XML 的 Mapper 配置文件來實現,也可以使用基於 Java 註解的 MyBatis 註解來實現,甚至可以

OrCAD: Capture CIS重要概念:instance 和 occurrences

用OrCAD設計原理圖必須理解兩個概念instance 和 occurrences。對於元件放置、替換、修改屬性等很多操作都和這兩個概念有關。   拋開抽象的說明,我們用例項說明他們的區別。假如你在自己的元件庫中已經建立了一個元件AD8056(AD公司的運放)。

Linux重要知識點

1.對於一個需求:一個專案組有好幾個使用者,所有使用者在目錄中建立檔案,可以刪除自己的檔案,但不能刪除別人的檔案,它的實現方法如下: 沾滯位:首先知道沾滯位是針對目錄來設定的。 ——許可權位 實現方法: chmod +t file:設定目錄的沾滯位 chmod

《深入理解計算機系統》筆記:重要概念

執行程式系統 編譯系統 從原始碼文字檔案到可執行目標檔案的轉化由編譯系統(compilation system)完成 前處理器(cpp):hello.c —> hello.i 根據以字元 #

微信小程式,開發重要的知識點(加密解密,轉發,進入場景,session_key)

小程式的授權資訊:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/authorize.html   小程式的系統引數和進入場景引數等:https://developers.weixin.qq.com/

微積分重要的不等式:Jensen不等式、平均值不等式、Holder不等式、Schwarz不等式、Minkovski不等式 及其證明

一:幾個重要不等式的形式 1,Jensen不等式 2,平均值不等式 3,一個重要的不等式 4,Holder不等式 5,Schwarz不等式 和 Minkovski不等式

MySQL JDBC URL重要引數說明

http://www.cnblogs.com/yokoboy/archive/2013/03/01/2939315.html jdbc:mysql://[host:port],[host:port].../[database][?引數名1][=引數值1][&引數名2

關於ORACLE資料庫名以及資料例項名等重要概念

在Oracle中有關資料庫和資料庫例項的幾個重要概念,有時候如果理解不是很深或者對其疏忽、混淆了,還真容易搞錯或弄不清其概念,下面就資料庫例項名、資料庫名、資料庫域名、資料庫服務名、全域性資料庫名幾個概念,我們來梳理一下概念,總結歸納一下這些知識,首先,我們來看看官方文件對這幾者的概念介紹:  

spring-aop的重要概念

弄清楚幾個概念: aop 即面向切面程式設計。什麼是切面,切面即重複程式碼。換而言之即面向重複程式碼程式設計。於是有了切面類Aop,裡面定義了會被重複使用的各個方法。 而切入點表示式:這個點是指攔截哪

USB HID協議關鍵概念的理解

USB HID描述符的體系結構如下:在Interface描述符中,HID裝置的:    1. bInterfaceClass值一定是3(HID Class);    2. bInterfaceSubClass的值可能為:0 (No Subclass), 1(Boot Inte

Mybatis重要

本文基於Mybatis3.2.0版本的程式碼。 1.org.apache.ibatis.mapping.MappedStatement MappedStatement類在Mybatis框架中用於表示XML檔案中一個sql語句節點,即一個<select />、&

Spring Aop重要概念,切點,切面,連線點,通知

直說正題: 1. 通知: 就是我們編寫的希望Aop時執行的那個方法。我們通過Aop希望我們編寫的方法在目標方法執行前執行,或者執行後執行。 2. 切點:切點就是我們我們配置的滿足我們條件的目標方法。比

Kubernetes 的重要概念

Cluster Cluster 是計算、儲存和網路資源的集合,Kubernetes 利用這些資源執行各種基於容器的應用。 Mast

掌握Rabbitmq重要概念,從一條訊息說起

RabbitMQ 是功能強大的開源訊息代理。根據官網稱:也是使用量最廣泛的訊息佇列。就像他的口號“Messaging that just works”,開箱即用使用簡單,支援多種訊息傳輸協議(AMQP、STOMP、MQTT)。 一個應用程式或者服務如何使用RabbitMq呢? 首先會有

簡單區分軟體開發概念:C/S結構和B/S結構、層結構和兩層結構、MVC和層架構

C/S——客戶端/服務端,簡單講就是客戶端電腦上需要安裝專有的軟體來更伺服器交流,就像QQ。主要通過訊息的機制傳遞(當然也可以自己寫協議,遊戲就是這樣做的。) B/S——瀏覽器/服務端,你只要有瀏覽器就可以與伺服器進行通訊,不用再安裝專門的客戶端,通訊協議使用HTTP協議.