亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

Maven 的聚合與繼承

通常情況下,我們在實際開發過程中,會對項目進行模塊(module)劃分,來提供項目的清晰度并且能夠更加方便的重用代碼。但是,在這種時候,我們在構建項目的時候就需要分別構建不同的模塊,Maven 的聚合特性能夠將各個不同的模塊聚合到一起來進行構建。而繼承的特性,則能夠幫助我們抽取各個模塊公用的依賴、插件等,實現配置統一。

1. 聚合

這里我們以一個簡單的 mall 項目作為例子。先來看一下這個項目的結構,整個項目包括 mall-core 和 mall-account 兩個功能模塊和 mall-aggregator 一個聚合模塊。其中, mall-core 處理商城項目的核心業務邏輯, mall-account 用于管理商城的賬戶信息。

項目文件圖示

一般來說,對于只有一個模塊的項目,我們可以在該模塊下直接執行 mvn clean package 命令來進行項目構建,但是,對于這樣的多模塊項目,我們如果要構建不同模塊的話,需要分別在對應模塊下執行 Maven 的相關命令,這樣看起來是非常繁瑣的。這個時候,Maven 的聚合特性就能夠起到作用。

我們來分析一下這個項目整體的結構,首先,我們看一下 mall-aggregator 模塊。這個模塊作為整個工程的聚合模塊,并沒有實際的代碼,但是其本身也是一個 Maven 項目,所以,也會存在 pom.xml 文件。那我們首先來看一下這個 pom.xml 文件有什么特點。

mall-aggregator 模塊的 pom.xml 文件

我們可以看到這里面也會有相對應的 groupId , artifactId , version ,packaging 信息,其中 packaging 的值必須是 pom,否則聚合項目無法構建。我們從 modules 中可以看到整個項目包含兩個模塊,分別是 mall-core 和 mall-account 。通常情況下,我們將不同的模塊放到聚合模塊下,其中 module 的值分別對應不同模塊的 artifactId 值。

在這個時候,我們 mall-aggregator 模塊下,使用 mvn clean package 來進行構建,可以將兩個模塊同時打包完成。

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] mall-aggregator                                                    [pom]
[INFO] mall-core                                                          [jar]
[INFO] mall-account                                                       [jar]
[INFO]
[INFO] ----------------------< com.mic:mall-aggregator >-----------------------
[INFO] Building mall-aggregator 1.0.0-SNAPSHOT                            [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ mall-aggregator ---
[INFO]
[INFO] -------------------------< com.mic:mall-core >--------------------------
[INFO] Building mall-core 1.0.0-SNAPSHOT                                  [2/3]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ...
[INFO] ------------------------< com.mic:mall-account >------------------------
[INFO] Building mall-account 1.0.0-SNAPSHOT                               [3/3]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for mall-aggregator 1.0.0-SNAPSHOT:
[INFO]
[INFO] mall-aggregator .................................... SUCCESS [  0.494 s]
[INFO] mall-core .......................................... SUCCESS [  2.152 s]
[INFO] mall-account ....................................... SUCCESS [  0.145 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  3.002 s
[INFO] Finished at: 2020-05-05T11:32:54+08:00
[INFO] ------------------------------------------------------------------------

從這次構建的過程來看,我們可以看出,Maven 會首先解析聚合模塊的 pom.xml 文件,分析出有哪些模塊需要構建,進而計算出一個反應堆構建順序(Reactor Build Order),并且根據這個順序來依次進行模塊的構建。

2. 繼承

2.1 繼承特性

現在我們解決了同時構建不同模塊同時構建的問題,但是,對于多模塊項目來說,還是會有些其他的問題存在,例如,不同模塊間有相同的 groupId,version ;有時候,也會需要引入相同的依賴。這個時候,如果每個模塊都重復引入的話,結果就會造成冗余。作為一個遵循面向對象的程序員來講,這樣的做法顯然是不合理的。

因此,Maven 也引入了類似的機制來解決這個問題,就是繼承的特性。

類似于 Java 中的父類與子類,我們也可以創建一個父模塊,讓其他的模塊作為子模塊來繼承該模塊,從而繼承父模塊中聲明的依賴以及配置。

對于父模塊來說,只是作為配置的公共模塊,是不需要代碼的,而且 pom.xml 文件中的 packaging 方式也是 pom,因此,我們可以將聚合模塊同時作為父模塊來使用,沒有必要再創建一個父模塊。(當然,這里也是可以單獨創建父模塊的)

此時,我們查看 mall-core 或者 mall-account 的 pom.xml 文件。
圖片描述

mall-core 模塊的 pom.xml 文件

我們可以看到 mall-core 模塊繼承了父模塊的坐標信息,并重新定義了 artifactId 。這時候,我們在父模塊引入一個依賴,然后查看 mall-core 模塊的 pom.xml 文件,會發現,在 mall-core 模塊中也會引入這個依賴。但是,實際上,我們并沒有在 mall-core 模塊中顯式的聲明這個依賴。

2.2 依賴管理

其實問題并沒有完全解決,并不是所有的子模塊都需要引入 fastjson-1.2.49.jar 這個依賴,那要怎么辦呢?

在 POM 中,我們可以在父模塊中聲明 dependencyManagement 元素,讓子模塊來繼承。dependencyManagement 元素并不會實際的引入依賴,但是可以起到很好的約束依賴的作用。

首先,我們在父模塊的 pom.xml 文件中聲明這個元素,并加入 fastjson-1.2.49.jar 這個依賴。

<properties>
    <fastjson.version>1.2.49</fastjson.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
	</dependencies>
</dependencyManagement>

然后,我們在 mall-core 模塊中添加這個依賴,但是我們并不需要再聲明version。

<dependencies>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
    </dependency>
</dependencies>

這時候,我們分別查看父模塊與子模塊所引入的依賴,會發現,只有子模塊中有引入這個依賴,而父模塊中,并沒有。

父模塊依賴引入情況
而子模塊中已經引入了這個依賴。
子模塊依賴引入情況

我們通過 Maven 繼承的特性,來進行依賴管理,可以更好的控制依賴的引入。而 Maven 對于插件的管理,也存在類似的元素可以使用(pluginmanagement 元素),可以做到相同的效果。

3. 反應堆

反應堆指的是整個項目中所有模塊的構建結構。在本節的例子中,整個構建結構包括三個模塊。反應堆不僅僅包括模塊本身,還包括了這三個模塊直接的相互依賴關系。

現在,我們的示例項目中,mall-core 和 mall-account 是不存在依賴關系的。父模塊中模塊的配置順序如下:

<!-- 模塊配置 -->
<modules>
    <module>mall-core</module>
    <module>mall-account</module>
</modules>

這里我們稍微做一下調整,用戶管理模塊可以提供接口給核心業務模塊來調用,因此,在 mall-core 模塊中引入 mall-account 依賴。重新進行項目構建。

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] mall-aggregator                                                    [pom]
[INFO] mall-account                                                       [jar]
[INFO] mall-core                                                          [jar]
[INFO]
[INFO] ----------------------< com.mic:mall-aggregator >-----------------------
[INFO] Building mall-aggregator 1.0.0-SNAPSHOT                            [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ mall-aggregator ---
[INFO]
[INFO] ------------------------< com.mic:mall-account >------------------------
[INFO] Building mall-account 1.0.0-SNAPSHOT                               [2/3]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ...
[INFO] -------------------------< com.mic:mall-core >--------------------------
[INFO] Building mall-core 1.0.0-SNAPSHOT                                  [3/3]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for mall-aggregator 1.0.0-SNAPSHOT:
[INFO]
[INFO] mall-aggregator .................................... SUCCESS [  0.220 s]
[INFO] mall-account ....................................... SUCCESS [  1.006 s]
[INFO] mall-core .......................................... SUCCESS [  0.132 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.533 s
[INFO] Finished at: 2020-05-05T14:25:48+08:00
[INFO] ------------------------------------------------------------------------

從構建的結果來看,模塊的構建順序并不是按照我們在父模塊中配置的順序進行的,而是 Maven 在經過分析之后,生成反應堆,根據反應堆的構建順序來進行構建的。

實際上,Maven 會根據模塊間繼承與依賴的關系來形成一個有向非循環圖,并根據圖中標記的順序,來生成反應堆構建順序,在構建的時候,根據這個順序來進行構建。本節中的實例項目的有向非循環圖如下:
圖片描述

繼承與依賴關系的有向非循環圖

在這個圖中,是不能出現循環的,假如我們在 mall-account 模塊中也添加入 mall-core 的依賴,再進行項目構建的時候,Maven 則會報錯出來,提示我們這個反應堆中存在循環引用。

[INFO] Scanning for projects...
[ERROR] [ERROR] The projects in the reactor contain a cyclic reference: Edge between 'Vertex{label='com.mic:mall-account:1.0.0-SNAPSHOT'}' and 'Vertex{label='com.mic:mall-core:1.0.0-SNAPSHOT'}' introduces to cycle in the graph com.m
ic:mall-core:1.0.0-SNAPSHOT --> com.mic:mall-account:1.0.0-SNAPSHOT --> com.mic:mall-core:1.0.0-SNAPSHOT @
[ERROR] The projects in the reactor contain a cyclic reference: Edge between 'Vertex{label='com.mic:mall-account:1.0.0-SNAPSHOT'}' and 'Vertex{label='com.mic:mall-core:1.0.0-SNAPSHOT'}' introduces to cycle in the graph com.mic:mall-
core:1.0.0-SNAPSHOT --> com.mic:mall-account:1.0.0-SNAPSHOT --> com.mic:mall-core:1.0.0-SNAPSHOT -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/ProjectCycleException

4. 小結

在本節的學習中,我們使用一個示例項目演示了 Maven 聚合與繼承兩個特性,以及兩者之間的關系,最后介紹了 Maven 構建項目時候,反應堆構建順序的生成,以及一些注意事項。