用了 Maven 好幾年了,許多人還是隻懂得簡單的依賴坐标。對于 Maven 的聚合和繼承還是一知半解,甚至很多人以為是同一個東西。但其實聚合是用于快速建構項目,是表示項目與子項目之間的關系。而繼承則是為消除重複的配置。下面通過一個例子深入聊聊這兩者的關系。
聚合
Maven 的聚合其實就是項目與子項目的表示,其存在的意義在于快速建構項目。例如我們有一個淘寶商城項目,這個項目有賬号子項目和郵件子項目。在這個時候我們需要在 Maven 中表達這種項目歸屬關系,那麼我們就可以用 Maven 的聚合來進行配置。
我們首先建立一個 taobao-aggregator 項目,表示是一個聚合項目。之後再建立兩個子項目,分别為:com.chenshuyi.mail 和 com.chenshuyi.account。
//taobao-aggregator pom.xml
<groupId>com.chenshuyi</groupId>
<artifactId>taobao-aggregator</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>taobao-aggregator</name>
<modules>
<module>mail</module>
<module>account</module>
</modules>
可以看到 taobao-aggregator 的 pom.xml 檔案中多了一個 modules 元素,其中包含了兩個子子產品。在 Maven 中我們通過 modules 元素來表示子產品之間的關聯關系。
在 Maven 的聚合關系中,聚合項目知道哪些項目是它的子項目,但是那些被聚合的項目并不知道其被哪個子產品聚合了。
一般情況下子項目都是在父項目的子目錄下,但你也可以把子項目放在與父項目同級的地方,隻要你修改一下
module
元素的值即可。
//taobao/account/mail同級
<modules>
<module>../account</module>
<module>../mail</module>
</modules>
繼承
Maven 的繼承是為了消除重複配置而存在的。例如我們的 account 子子產品和 mail 子子產品都需要 junit-test 依賴,但是都得在自己的子產品裡都寫一次,這樣豈不是會造成代碼的重複。這個時候就可以将共同的依賴寫在父類子產品中,讓子類繼承這些依賴。
例如 taobao-parent 是 mail 子產品和 account 子產品的父子產品,他們都需要 junit 測試依賴包。那麼此時在 taobao-parent 項目的 dependencies 元素中聲明該依賴。
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
mail 子產品和 account 子產品中增加一個 parent 元素聲明,表明其父級是 taobao-parent 項目。
<parent>
<artifactId>taobao-parent</artifactId>
<groupId>com.chenshuyi</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
經過這麼一個配置之後,Maven 就隻知道他們的依賴關系。此時 taobao 項目 dependencies 元素裡聲明的依賴就會全部繼承到子項目中。這樣子項目中就不需要再去聲明多一次了,節省了不必要的配置。
像 dependencies 這樣可以被子類繼承的元素還有下面幾個元素:
- groupId
- version
- description
- organization
- inceptionYear
- url
- developers
- contributors
- distributionManagement
- issueManagement
- ciManagement
- scm
- mailingLists
- properties
- dependencies
- dependencyManagement
- repositories
- build
- reporting
聚合與繼承的關系
從上面可以看到多子產品 Maven 項目中的聚合與繼承其實是兩個概念,其目的是完全不同的。聚合是為了友善快速建構項目,繼承是為了消除重複配置。
對于聚合子產品來說,它知道哪些被聚合的子產品(通過modules元素),但那些被聚合的子產品不知道這個聚合子產品的存在。
對于繼承關系的父 POM 來說,它不知道哪些子子產品繼承于它,但那些子子產品都必須知道自己的父 POM 是什麼。
在實際項目中,大家會發現一個 pom 即是聚合 pom,又是父 pom,這麼做主要是為了友善。就像上面我們定義的聚合子產品為 taobao-aggregator,父級子產品為 taobao-parent,我們可以将其合并成為一個名為 taobao 的 pom 檔案。這樣清晰明了。
總結
如果看完本文還是不了解,那麼可以自己去看下《Maven實戰》中關于聚合和繼承的講解,裡面講得更加細緻。