Maven聚合與繼承

1、聚合

Maven聚合(或者稱爲多模塊),是爲了能夠使用一條命令就構建多個模塊,例如已經有兩個模塊,分別爲account-email,account-persist,我們需要創建一個額外的模塊(假設名字爲account-aggregator,然後通過該模塊,來構建整個項目的所有模塊,accout-aggregator本身作爲一個Maven項目,它必須有自己的POM,不過作爲一個聚合項目,其POM又有特殊的地方,看下面的配置:

<project
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/maven-v4_0_0.xsd>
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.juvenxu.mvnbook.account</groupId>
        <artifact>account-aggregator</artifact>
        <version>1.0.0-SNAPSHOT</version>
        <packaging>pom</packaging>
        <name>Account Aggregator</name>
        <modules>
            <module>account-email</module>
            <module>account-persist</module>
        </modules>
</project>

上面有一個特殊的地方就是packaging,其值爲pom,如果沒有聲明的話,默認爲jar,==對於聚合模塊來說,其打包方式必須爲pom==,否則無法構建。

modules裏的每一個module都可以用來指定一個被聚合模塊,這裏每個module的值都是一個當前pom的相對位置,本例中account-email、account-persist位於account-aggregator目錄下,當三個項目同級的時候,上面的兩個module應該分別爲../account-email和../account-persist

2、繼承

在構建多個模塊的時候,往往會多有模塊有相同的groupId、version,或者有相同的依賴,例如:spring-core、spring-beans、spring-context和junit等,或者有相同的組件配置,例如:maven-compiler-plugin和maven-resources-plugin配置,在Maven中也有類似Java的繼承機制,那就是POM的繼承。

繼承POM的用法

面向對象設計中,程序員可以通過一種類的父子結構,在父類中聲明一些字段和方法供子類繼承,這樣可以做到“一處聲明、多處使用”,類似的我們需要創建POM的父子結構,然後在父POM中聲明一些配置,供子POM繼承。

下面聲明一個父POM,如下:

<project
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:shemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juvenxu.mvnbook.account</groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Parent</name>
</project>

這個父POM中,groupId和version和其它模塊一樣,它的packaging爲pom,這一點和聚合模塊一樣,==作爲父模塊的POM,其打包類型也必須爲pom==,由於父模塊只是爲了幫助消除配置的重複,因此它本身不包含除POM之外的項目文件,也就不需要src/main/java之類的文件夾了。

有了父模塊,就需要其它模塊來繼承它。首先將account-email的POM修改如下:

account-email繼承account-parent的POM

<project
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:shemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
    <parent>
        <groupId>com.juvenxu.mvnbook.account<groupId>
        <artifactId>account-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../account-parent/pom.xml</relativePath>
    </parent
    
    <artifactId>account-email</artifactId>
    <name>Account Email</name>
    
    <dependencies>
        ....
    </dependencies>
    <build>
        <plugins>
            ....
        </plugins>
    </build>
</project>

上面POM中使用parent元素聲明父模塊,==paren下的子元素groupId、artifactId和version指定了父模塊的座標,這三個元素是必須的==。元素relativePath表示了父模塊POM的相對位置。當項目構建時,Maven會首先根據relativePath檢查父POM,如果找不到,再從本地倉庫查找。relativePath的默認值是../pom.xml,Maven默認父POM在上一層目錄下。

上面POM沒有爲account-email聲明groupId,version,不過並不代表account-email沒有groupId和version,實際上,這個子模塊隱式的從父模塊繼承了這兩個元素,這也就消除了不必要的配置。上例中,父子模塊使用了相同的groupId和version,如果遇到子模塊需要使用和父模塊不一樣的groupId或者version的情況,可以在子模塊中顯式聲明。對於artifactId元素來說,子模塊更應該顯式聲明,因爲如果完全繼承groupId、artifactId、version,會造成座標衝突;另一方面,即使使用不同的groupId或version,同樣的artifactId容易造成混淆。

account-persist繼承account-parent的POM

<project
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:shemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
    <parent>
        <groupId>com.juvenxu.mvnbook.account<groupId>
        <artifactId>account-parent</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../account-parent/pom.xml</relativePath>
    </parent
    
    <artifactId>account-persist</artifactId>
    <name>Account Persist</name>
    
    <dependencies>
        ....
    </dependencies>
    <build>
        <testResources>
            <testResource>
                <directory>src/test/resources</directory>
                <filtering>true</filtering>
            </testResource>
        </testResources>
        <plugins>
            ....
        </plugins>
    </build>
</project>

最後,同樣需要把account-parent加入到聚合模塊accountp-aggregator中,代碼如下:

將account-parent加入到聚合模塊

<project
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
        http://maven.apache.org/maven-v4_0_0.xsd>
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.juvenxu.mvnbook.account</groupId>
        <artifact>account-aggregator</artifact>
        <version>1.0.0-SNAPSHOT</version>
        <packaging>pom</packaging>
        <name>Account Aggregator</name>
        <modules>
            <module>account-email</module>
            <module>account-persist</module>
            <module>account-parent</module>
        </modules>
</project>

可繼承的POM元素

  • groupId:項目組ID,項目座標的核心元素
  • version:項目版本,項目座標的核心元素
  • description:項目的描述信息
  • organnization:項目的組織信息
  • inceptionYear:項目的創始年份
  • url:項目的URL地址
  • developers:項目的開發者信息
  • contributors:項目的貢獻者信息
  • distributionManagement:項目的部署配置
  • issueManagement:項目的缺陷跟蹤系統信息
  • ciManagement:項目的集成信息
  • scm:項目的版本控制系統信息
  • mailingLists:項目的郵件列表信息
  • properties:自定義的Maven屬性
  • dependencies:項目的依賴配置
  • dependencyManagement:項目的依賴管理配置
  • repositories:項目的倉庫配置
  • build:包括項目的源碼目錄配置、輸出目錄配置、插件配置、插件管理配置等
  • reporting:包括項目的報告輸出目錄配置,報告插件配置等。

依賴管理

當多有模塊中有相同的依賴時,我們可以將這些依賴提取出來,統一在父POM中聲明,這樣就可以簡化子模塊的配置了,但是這樣還是存在問題,當想項目中加入一些,不需要這麼多依賴的模塊,如果讓這個模塊也依賴那些不需要的依賴,顯然不合理。

Maven提供的dependentcyManagement元素既能讓子模塊繼承到父模塊的依賴配置,又能保證子模塊依賴使用的靈活度。在dependentcyManagement元素下的依賴聲明不會引入實際的依賴,不過他能夠約束denpendencies下的依賴使用。對上面的accoun-parent進行改進,代碼如下:

<project
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:shemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juvenxu.mvnbook.account</groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Parent</name
    <properties>
        <springframework.version>2.5.6</springframework.version>
        <junit.version>4.7</junit.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${springframework.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

上面使用了dependencyManagement聲明的依賴既不會給account-parent引入依賴,也不會給它的子模塊引入依賴,不過這段配置是會被繼承的。

修改account-email的POM如下:

繼承dependencyManagement的account-email POM

<properties>
    <javax.mail.version>1.4.1</javax.mail.version>
    <greenmail.version>1.3.1b</greenmail.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>${javax.mail.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.icegreen</groupId>
            <artifactId>greenmail</artifactId>
            <version>${greenmail.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

子模塊只需要配置簡單的groupId和artifactId就能獲得對應的依賴信息,從而引入正確的依賴。

這種依賴管理機制似乎不能減少太多的POM配置,但是其好處很大,原因在於在POM中使用dependencyManagement聲明依賴能夠統一規範項目中依賴的版本,當依賴的版本在父POM中聲明之後,子模塊在使用依賴的時候就無效聲明版本,也就不會發生多個子模塊使用依賴版本不一致的情況。這可以降低依賴衝突的機率。

如果在子模塊不聲明依賴的使用,即使該依賴已經在父POM的dependencyManagement中聲明瞭,也不會產生任何實際的效果。

如果子模塊不聲明依賴的使用,即使該依賴已經在父POM的dependencyManagement中聲明瞭,也不會產生任何實際的效果,如account-persist的POM。

<properties>
    <dom4j.version>1.6.1</dom4j.version>
</properties>
<dependencies>
    <dependency>
        <groupId>dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>dom4j.version</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
</dependencies>

這裏沒有聲明spring-context-support,那麼該依賴就不會被引入。這正是dependencyManagement的靈活性所在

  • 另外,依賴範圍有個import範圍,import依賴範圍只有在dependencyManagement下才有效果,使用該範圍的依賴通常指向一個POM,作用是將目標中的dependencyManagement配置導入到當前POM的dependencyManagement中配置,除了複製配置或者繼承這兩種方式之外,還可以使用import範圍依賴將這一配置導入。

使用import範圍依賴導入依賴管理配置

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.juvenxu.mvnbook.account<groupId>
            <artifactId>account-parent</artifactId>
            <version>1.0-SNAPSHOT</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

注意,上面代碼中依賴的type爲pom,import依賴範圍由於其特殊性,一般都指向打包類型爲pom的模塊。如果有多個項目,他們使用的依賴版本都是一致的,則可以定義一個dependencyManagement專門管理依賴的POM,然後在各個項目中導入這些依賴管理配置。

插件管理

Maven提供了dependencyManagement元素幫忙管理依賴,類似地,Maven也提供了pluginManagement元素幫忙管理插件。該元素中配置的依賴不會造成實際的插件調用行爲,當POM中配置了真正的plugin元素,並且其groupId和artifactId與pluginManagement中配置的插件匹配時,pluginManagement的配置纔會影響實際的插件行爲。

前面有如何通過組件去將jar-no-fork目標綁定到verity生命週期階段,以生成項目源碼包。如果一個項目中有很多子模塊,並且需要這些模塊的源碼包,那麼很顯然,爲所有模塊重複類似的插件配置不是最好的辦法,這時最好的辦法是在父POM中使用pluginManagement配置插件,代碼如下:

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>2.1.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

當子模塊需要生成源碼包的時候,只需要如下簡單的配置,代碼如下:

子模塊聲明使用了maven-source-plugin插件,同時又繼承了父模塊的pluginManagement配置,兩者基於groupId和artifactId匹配合並。

有了pluginManagement元素,accout-email和accout-persist的POM也能得以簡化了他們都配置了maven-compiler-plugin和maven-resources-plugin。可以將這兩個插件的配置移到account-parent的pluginManagement元素中,代碼如下:

<build>
    <pluginMangement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifact>maven-resources-plugin</artifact>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </pluginMangement>
</build>

accout-email和account-persist可以完全地移除關於maven-compiler-plugin和maven-resources-plugin的配置,但他們仍然能享受這這個插件的服務,前一插件開啓了jdk1.5編譯的支持,後一插件也會使用UTF-8編碼處理資源文件。這背後涉及了很多Maven機制,首先,內置的插件綁定關係將兩個插件綁定到了account-email和account-persist生命週期上,其次,超級POM爲這兩個插件申明瞭版本;最後,account-parent中的pluginManagement對這兩個插件的行爲進行了配置。

當項目中的多個模塊有同樣的插件配置時,應當將配置移到父POM的pluginMangement元素中。即使各個模塊對於同一插件的具體配置不盡相同,也應當使用父POM的pluginManagement元素同意聲明插件的版本。甚至可以要求將所有用到的插件的版本在父POM的pluginManagement中聲明,子模塊使用插件時不配置版本信息,這麼做可以統一項目的插件版本,避免潛在的插件不一致或者不穩定的問題,也更易於維護。

3、聚合與繼承的關係

多模塊中的聚合與繼承其實是兩個概念,其目的是完全不同的,前者主要是爲了方便快速構建項目,後者主要是爲了消除重複配置。

對於聚合模塊來說,它知道有哪些被聚合的模塊,但那些被聚合的子模塊不知道這個聚合模塊的存在。

對於繼承關係的父POM來說,它不知道哪些子模塊繼承於它,但那些子模塊都必須知道自己的父POM是什麼。

                                                                                   聚合關係與繼承關係的比較

在現有的實際項目中,往往會發現一個POM既是聚合POM,又是父POM,這麼做主要是爲了方便。一般來說,融合使用聚合與繼承也沒什麼問題,例如可以將account-aggretor和account-parent其POM如下:

<project xmlns="http://maven-apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juvenxu.mvnbook.account</groupId>
    <artifactId>account-parent</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <name>Account Parent</name>
    <modules>
        <module>account-persist</module>
    </modules>
    <properties>
        <springframework.version>2.5.6</springframework.version>
        <junit.version>4.7</junit.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${springframework.version}</version>
            </dependency>
           <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${springframework.version}</version>
            </dependency>
            <dependency>
                <groupId>junit<groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.5</source>
                        <target>1.5</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-resource-plugin<artifactId>
                    <configuration>
                        <endcoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build
</project>

可以看到POM的打包方式爲pom,它包含了一個modules元素,表示用來聚合account-persist和account-email兩個模塊,它還包含了properties、dependencyManagement和pluginManagement元素供子模塊繼承。

4、約定優於配置

Maven默認的源碼目錄是:src/main/java但是用戶也可以自己指定源碼目錄,如下:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.juvenxu.mvnbook<groupId>
    <artifactId>my-project</artifactId>
    <version>1.0</version>
    <build>
        <sourceDirectory>src/java</sourceDirectory>
    </build>
</project>

上面配置就將源碼目錄改爲src/java而不是默認的src/main/java

任何一個Maven項目都隱式的繼承自該POM,這有點類似任何一個Java類都隱式的繼承於Object類,因此,大量超級POM的配置都會被所有Maven項目繼承,這些配置也就成爲了Maven所提倡的約定。

對於Maven3,超級POM在文件$MAVEN_HOME/lib/maven-model-builder-x.x.x.jar中的org/apache/maven/model/pom-4.0.0.xml路徑下。對於Maven2,超級POM在文件$MAVEN_HOME/lib/maven-x.x.x-uber.jar中的org/apache/maven/project/pom-4.0.0.xml目錄下。

超級POM的內容在Maven2和Maven3中基本一致,分段看一下,見代碼:

<repositories>
    <repository>
        <id>central</id>
        <name>Maven Repository Switchboard</name>
        <url>http://repo1.maven.org/maven2</url>
        <layout>default</layout>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>central</id>
        <name>Maven Plugin Repository</name>
        <url>http://repo1.maven.org/maven2</url>
        <layout>default</layout>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
        <releases>
            <updatePolicy>never</updatePolicy>
        </releases>
    </pluginRepository>
</pluginRepositories>

超級POM定義了倉庫及插件倉庫,兩者的地址都是爲中央倉庫http://repo1.maven.org/maven2,並且都關閉了SNAPSHOT的支持,這也就解釋了爲什麼Maven默認就可以按需要從中央倉庫下載構件。

超級POM中關於項目結構的定義:

<build>
    <directory>${project.basedir}/target<directory>
    <outputDirectory>${project.build.directory}/classes</outputDirectory>
    <finalName>${project.artifactId}-${project.version}</finalName>
    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
    <scriptSourceDirectory>src/main/script</scriptSourceDirectory>
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
    <resources>
        <resource>
            <directory>${project.basedir}/src/main/resources</directory>
        </resource>
    </resources>
    <testResources>
        <testResource>
            <directory>${project.basedir}/src/test/resources</directory>
        </testResource>
    </testResources>

這裏依次定義了項目的主輸出目錄,主代碼輸出目錄,最終構件的名稱格式、測試代碼輸出格式、主源碼目錄,腳本源碼目錄、測試源碼目錄、主資源目錄和測試資源目錄。這就是Maven項目結構的約定。

接着,超級POM爲核心差勁設定版本,代碼如下:

<pluginManagement>
    <plugins>
        <plugin>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.3</version>
        </plugin>

        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2-bete-4</version>
        </plugin>
        
        <plugin>
            <artifactId>maven-clean-plugin</artifactId>
            <version>2.3</version>
        </plugin>
        
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.0.2</version>
        </plugin>
        ........
    </plugins>
</pluginManagement>

</build>

5、反應堆

在一個多模塊的Maven項目中,反應堆(Reactor)是指所有模塊組成的一個構建結構。對於單模塊的項目,反應堆就是該模塊本身,對於多模塊來說,反應堆就包含了各模塊之間繼承與依賴的關係,從而能夠自動計算出合理的模塊構建順序。

例如修改account-aggregator的聚合配置:

<modules>
    <module>account-email</module>
    <module>account-persist</module>
    <module>account-parent</module>
</modules>

構建account-aggregator,會看到如下輸出:

[INFO] -----------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] Account Aggregator
[INFO] Account Parent
[INFO] Account Email
[INFO] Account Persist
[INFO]
[INFO] -----------------------------------------

以上,構建順序不一定是順序去讀取POM的順序。當一個模塊依賴於另外一個模塊,Maven會先去構建被依賴模塊,如果被依賴的模塊還依賴其他模塊,則進一步先構建依賴的依賴。

                                                                                          賬戶註冊服務4個模塊的反應堆

從上到下的箭頭表示pom的讀取次序,從右至左的箭頭表示模塊之間的繼承或者依賴。模塊間的依賴(泛指依賴或者繼承)關係會將反應堆構成一個有向非循環圖(Directed Acyclic Graph,DGA),各個模塊是該圖的節點,依賴關係構成有向邊。這個圖不允許出現循環,因此,當出現模塊A依賴於B,而B又依賴於A的情況時,Maven就會報錯。

裁剪反應堆

一般來說,用戶會選擇構建整個項目或者選擇構建單個的模塊,但有些時候,用戶會想要僅僅構建完整反應堆中的某些個模塊。換句話說,用戶需要實時地剪裁反應堆。

Maven提供很多命令行選項支持裁剪反應堆,輸入mvn -h可以看到這些選項:

  • -am, --also-make 同時構建所列模塊的依賴模塊
  • -amd -also-make-dependents 同時構建依賴於所列模塊的模塊
  • -pl,--project <arg> 構建指定的模塊,模塊間用逗號分隔
  • -rf -resume-from <arg> 從指定的模塊回覆反應堆

默認情況從account-aggregator執行mvn clean install會得到如下完整的反應堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Aggregator
[INFO]Account Parent
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

可以使用-pl選項指定構建某幾個模塊,如運行如下命令:

$ mvn clean install -pl account-email,account-persist

得到的反應堆爲:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

使用-am選項可以同時構建所列模塊的依賴模塊,例如:

$ mvn clean install -pl account-email -am

由於account-email依賴於account-parent,因此會得到如下反應堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Parent
[INFO]Account Email
[INFO]
[INFO]-----------------------------------------------------

使用-amd選項可以同時構建依賴於所列模塊的模塊。例如:

$ mvn clean install -pl account-parent -amd

由於account-email和account-persist都賴於account-parent,因此會得到如下反應堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Parent
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

使用-rf選項可以在完整的反應堆構建順序基礎上指定從哪個模塊開始構建。例如:

$mvn clean install -rf account-email

完整的反應堆構建順序中,account-email位於第三,它之後只有account-persist因此會得到如下的剪裁反應堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

最後在-pl -am或者-pl -amd的基礎上,還能應用-rf參數,以對裁剪後的反應堆再次剪裁,例如:

$ mvn clean install -pl account-parent -amd -rf account-email

該命令中的-pl和-amd參數會裁剪出一個account-parent、account-email和account-persist的反應堆,在此基礎上,-rf參數指定從account-email參數構建。因此會得到如下的反應堆:

[INFO]-----------------------------------------------------
[INFO]Reactor Build Order:
[INFO]
[INFO]Account Email
[INFO]Account Persist
[INFO]
[INFO]-----------------------------------------------------

在開發過程中,靈活應用上述四個參數,可以幫助我們跳過無須構建的模塊,從而加速構建。在項目龐大、規模特別多的時候,這種效果就會異常明顯。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章