用了 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實戰》中關於聚合和繼承的講解,里面講得更加細致。