1. 程式人生 > >maven系列-(五)maven聚合和繼承

maven系列-(五)maven聚合和繼承

我們之前建立的這個maven-test專案,只包含一個模組。但是在實際開發中,由於業務龐大,經常會把一個大專案分為多個模組。或者是把controller、service、dao等業務層都作為一個模組。最上層是一個總的模組,裡面包含很多子模組,同時,最上層的模組還作為一個父模組,和子模組形成依賴關係。整個大專案形成一個父子工程的結構。

先回顧下我們maven-test的結構:
在這裡插入圖片描述

maven-test就是一個maven的模組,裡面有src目錄,可以在裡面編寫業務程式碼。
下面我們改造一下這個專案,在裡面建立幾個子模組。

聚合

先刪掉maven-test目錄下的src目錄,然後在maven-test上右鍵選擇新建module:
在這裡插入圖片描述


新建三個module:maven-test-controller、maven-test-service、maven-test-dao:

在這裡插入圖片描述

在maven-test的pom中可以看到多了下面的內容:

<packaging>pom</packaging>
<modules>
    <module>maven-test-controller</module>
    <module>maven-test-service</module>
    <module>maven-test-dao</module>
</modules>

maven-test就是聚合專案,裡面的maven-test-controller、maven-test-service、maven-test-dao是三個子模組。而maven-test作為聚合專案,一般會在目錄結構的最頂層,並且聚合專案的packaging必須要為pom。
經過maven的聚合,我們就可以通過命令來構建所有的這些模組,也可以只選擇一部分模組。
當選擇構建聚合模組時,maven就會解析聚合模組的pom檔案,分析要構建的模組,並且計算出一個反應堆構建順序,根據這個順序依次構建各個模組。
可以在命令列輸入 mvn clean install,看下打印出來的日誌,我這裡擷取一部分日誌貼出來:

mvn clean install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] maven-test                                                         [pom]
[INFO] maven-test-controller                                              [jar]
[INFO] maven-test-service                                                 [jar]
[INFO] maven-test-dao                                                     [jar]
.....省略.......
[INFO] Reactor Summary:
[INFO] 
[INFO] maven-test 1.0-SNAPSHOT ............................ SUCCESS [  0.801 s]
[INFO] maven-test-controller .............................. SUCCESS [  0.898 s]
[INFO] maven-test-service ................................. SUCCESS [  0.067 s]
[INFO] maven-test-dao 1.0-SNAPSHOT ........................ SUCCESS [  0.063 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.961 s
[INFO] Finished at: 2018-10-12T08:17:37+08:00
[INFO] ------------------------------------------------------------------------

從日誌中可以看到,maven先計算了構建順序,並且所有的模組都被構建了。
通過maven的聚合,我們就可以很靈活的構建專案,一個命令就可以把所有的專案構建了,而且還可以只構建專案中的某幾個模組,加快構建速度。

繼承

有了聚合,我們就可以在一個聚合專案中包含多個子模組,那就會有個問題,不同子模組中都會引入共同的依賴,造成太多的冗餘,這就需要用到maven的繼承了,在聚合模組中,一般都會有繼承。我們建立maven-test-controller、maven-test-service、maven-test-dao這三個模組中,在pom檔案中就可以看到下面的宣告:

<parent>
    <artifactId>maven-test</artifactId>
    <groupId>com.baidu.test</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>maven-test-controller</artifactId>

這就是maven-test-controller的pom檔案,裡面有個parent標籤,標識maven-test-controller的parent是maven-test模組。在maven-test-controller中也就只需要宣告artifactId的值即可,groupId和version預設繼承父模組的。當然,子模組也可以顯式的宣告groupId和version,但是一般的約定,都是要和父模組保持一致。

通過maven繼承,子模組就可以繼承父模組宣告的依賴,我們的程式碼中就不會有那麼多的冗餘了。除非子模組需要宣告新的依賴或者是子模組和父模組的依賴版本不一樣,才需要在子模組中進行宣告。

這種方式雖然可以在子模組中少很多宣告,其實並不推薦,因為子模組預設是繼承父模組中所有的宣告的,如果一個子模組本來不需要這些依賴,那也會預設繼承。可以在父模組中通過<dependencyManagement>標籤來讓子模組既能繼承到父模組的依賴配置,又能保持使用的靈活性。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.1.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

通過dependencyManagement元素宣告的依賴,不會實際引入子模組中,但是又能夠約束dependencies下的依賴使用。

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
</dependencies>

父模組通過dependencyManagement元素宣告的依賴後,子模組如果需要引入的依賴,就可以通過<dependency>顯式引入依賴,但是不需要宣告version,因為父專案中已經定義了version。如果子模組不宣告依賴的話,即使父模組在dependencyManagement聲明瞭,子模組也不會引入。
dependencyManagement對應,pluginManagement是對外掛進行同樣方式的宣告的,該元素中配置的依賴不會造成實際的外掛呼叫行為:

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.3</version>
                <configuration>
                    <attach>true</attach>
                </configuration>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

通過這種方式,就可以在父模組中統一專案範圍中依賴的版本,同時不會造成子模組多餘的引用,減少多個子模組之間獨自宣告出現的使用版本不一致的情況,降低依賴衝突的機率。

參考資料:
1.《maven實戰》 許曉斌 著