Maven(3)--聚合与继承
目錄
?
聚合
重點:
繼承
注意:
聚合與繼承的關系區別 :
共同點 :
Maven可繼承的POM 元素
依賴管理
import依賴范圍
插件管理
約定由于配置
反應堆
反應堆的構建順序
裁剪反應堆
聚合
假設項目【用戶注冊服務】包含模塊:account-email和 account-persist。我們需要進行全部構建,而不是在每個模塊目錄下都執行mvn命令進行構建。maven聚合(多模塊)特性就可以滿足此需求。
為了能夠使用一條命令就能構建 account-email和 account-persist兩個模塊,我們需要建立一個額外的名為 account-aggregator的模塊,然后通過該模塊構建整個項目的所有模塊。 account-aggregator本身也是個 Maven項目,它的 POM如下:
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.juvenxu.mvnbook.account</groupId> <artifactId>account-aggregator</artifactId> <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
- module的值是一個以當前POM為主目錄的相對路徑
繼承
可聲明父POM供子 POM繼承
父模塊POM如下:(packaging為pom)
<project> <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>子模塊聲明繼承如下:
<project> <modelVersion>4.0.0</modelVersion> < 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> ... </project>最后,同樣還需要把 account-parent加入到聚合模塊account-aggregator中。聚合的 POM如下:
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.juvenxu.mvnbook.account</groupId> <artifactId>account-aggregator</artifactId> <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>注意:
?
- 子模塊沒有聲明groupId和version, 這兩個屬性繼承至父模塊。但如果子模塊有不同與父模塊的 groupId、version ,也可指定;
- 不應該繼承artifactId,如果groupId ,version,artifactId 完全繼承的話會造成坐標沖突;另外即使使用不同的 groupId或version,同樣的 artifactId也容易產生混淆。
- 使用繼承后 parent也必須像自模塊一樣加入到聚合模塊中。也就是在在聚合模塊的 pom中加入<module>account-parent</module>
聚合與繼承的關系
區別 :
 
共同點 :
Maven可繼承的POM 元素
groupId :項目組 ID ,項目坐標的核心元素; ?
 version :項目版本,項目坐標的核心元素; ?
 description :項目的描述信息; ?
 organization :項目的組織信息; ?
 inceptionYear :項目的創始年份; ?
 url :項目的 url 地址 ?
 develoers :項目的開發者信息; ?
 contributors :項目的貢獻者信息; ?
 distributionManagerment :項目的部署信息; ?
 issueManagement :缺陷跟蹤系統信息; ?
 ciManagement :項目的持續繼承信息; ?
 scm :項目的版本控制信息; ?
 mailingListserv :項目的郵件列表信息; ?
 properties :自定義的 Maven 屬性; ?
 dependencies :項目的依賴配置; ?
 dependencyManagement :醒目的依賴管理配置; ?
 repositories :項目的倉庫配置; ?
 build :包括項目的源碼目錄配置、輸出目錄配置、插件配置、插件管理配置等; ?
 reporting :包括項目的報告輸出目錄配置、報告插件配置等。
依賴管理
Maven提供的dependencyManagement元素既能讓子模塊繼承到父摸塊的依賴配置,又能保證子模塊依賴使用的靈活性。在dependencyManagement元素下的依賴聲明不會引入實際的依賴,不過它能夠約束dependencies下的依賴使用。例如,可以在account-parent中加入:
<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></dependencies> </dependencyManagement>這段配置是會被繼承的,如在account-email中
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId></dependency> </dependencies>這樣做的好處:統一管理項目的版本號,確保應用的各個項目的依賴和版本一致,才能保證測試的和發布的是相同的成果,因此,在頂層pom中定義共同的依賴關系。同時可以避免在每個使用的子項目中都聲明一個版本號,這樣想升級或者切換到另一個版本時,只需要在父類容器里更新,不需要任何一個子項目的修改;如果某個子項目需要另外一個版本號時,只需要在dependencies中聲明一個版本號即可。子類就會使用子類聲明的版本號,不繼承于父類版本號。
import依賴范圍
import依賴范圍只在dependencyManagement元素下才又效果,使用該范圍的依賴通常指向一個POM,作用是將目標POM中的dependencyManagement配置導入并合并到當前POM的dependencyManagement元素當中。
<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元素,并且其groupld和artifactld與pluginManagement中配置的插件匹配時,pluginManagement的配置才會影響實際的插件行為。
例如maven-source-plugin配置了,將其jar-no-fork目標綁定到了verify生命周期階段,以生成源碼包,如果一個項目有很多模塊,并且需要得到所有這些模塊的源碼包,那么很顯然,為所有模塊重復類似的插件配置不是最好的方法,這時更好的方法是在父POM中使用pluginManagement配置插件。
<build><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><argifactId>maven-source-plugin</argifactId><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>而子模塊需要這樣配置:
<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-source-plugin</artifactId></plugin></plugins> </build>子模塊聲明使用了maven-source-plugin插件,同時又繼承了父模塊的pluginManagement配置,兩者基于groupId和artifactId匹配合并。如果子模塊不需要使用父模塊中pluginManagement配置的插件,可以盡管將其忽略,如果子模塊需要不同的插件配置,則可以自行配置以覆蓋父模塊的pluginManagement配置。
有了pluginManagement元素account-email和account-persist的POM也能得以簡化了,他們都配置了maven-compiler-plugin和maven-resources-plugin,可以將這兩個插件的配置移到account-parent的pluginManagement元素中。此時這兩個模塊可以完全的移除關于maven-compiler-plugin和maven-resources-plugin的配置,但他們仍可以享受這兩個插件的服務,前一個插件是開啟java 5編譯的支持,后一個是使用UTF-8編碼處理資源文件,這涉及了Maven很多機制,首先,內置的插件綁定關系將兩個插件綁定到了account-email和account-persist的生命周期上,其次,超級POM為這兩個插件聲明了版本,最后account-parent中的pluginManagement對這兩個插件的行為進行了配置。
所以將配置移到父POM的pluginManagement元素中,即使各個模塊對于同一插件的具體配置不盡相同,也應當使用父POM的pluginManagement元素統一聲明插件的版本,甚至可以要求將所有用到的插件的版本在父POM的pluginManagement元素中聲明,子模塊使用插件時不配置版本信息,可以統一插件的版本。
約定由于配置
這是Maven最核心的設計理念之一,約定可以減少配置,在Ant中需要做的就是清除構建目錄,編譯代碼,復制依賴至目標目錄。最后打包,這是構建最基本的事情,不過此時還是需要寫很多的XML配置,源碼什么,編譯目標和分發目錄時什么等等,用戶還需要記住各種Ant任務命令,如delete,mkdir,javac和jar,同樣是事情,Maven只需要一個最簡單的POM
<project> <modelVersion> 4.0.0</modelVersion> <groupId>com.juvenxu-mvnbook</groupId> <artifactId>my-project</artifactId> <version>1.0</version> </project>同時為了獲得這樣簡潔的配置,用戶需要付出一定的代價,那就是遵循Maven的約定,Maven會假設用戶的項目是這樣的:
??? 源碼目錄src/main/java
 ??? 編譯輸出目錄為target/classes/
 ??? 打包方式為jar,
 ??? 包輸出目錄為target/
遵循約定雖然會損失一定的靈活性,用戶不能隨便安排目錄,但是卻能減少配置,如果沒有約定,則10個項目可能使用10種不同的項目目錄結構,而有了Maven的約定大家都知道什么目錄放什么地方。此外,Ant的自定義目錄名稱不同,Maven則在命令行暴露的用戶接口是統一的,例如mvn clean install這樣的命令可以用來構建幾乎任何的Maven項目。
如果不想要遵守約定,但是個性往往意味著犧牲通用性,意味著增加無謂的復雜度,例如Maven允許使用你自定義源碼目錄。
<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>?此時源碼目錄就成了src/java了,往往造成交流問題,除非你在處理遺留代碼,并且沒有辦法更改原來的目錄結構,此時只能讓Maven妥協了。
前面多次提到的超級POM,任何一個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路徑下,超級POM的內容如下:
<pluginRepositories><pluginRepository><id>central</id><name>Central Repository</name><url>https://repo.maven.apache.org/maven2</url><layout>default</layout><snapshots><enabled>false</enabled></snapshots><releases><updatePolicy>never</updatePolicy></releases></pluginRepository></pluginRepositories>首先超級POM定義了倉庫和插件倉庫,兩者的地址都是中央倉庫http://repol.maven.org/maven2,并且關閉了SNAPSHOT的支持,這也解釋了為什么Maven默認就可以按需要從中央倉庫下載構件。
<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>${project.basedir}/src/main/scripts</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><pluginManagement><!-- NOTE: These plugins will be removed from future versions of the super POM --><!-- They are kept for the moment as they are very unlikely to conflict with lifecycle mappings (MNG-4453) --><plugins><plugin><artifactId>maven-antrun-plugin</artifactId><version>1.3</version></plugin><plugin><artifactId>maven-assembly-plugin</artifactId><version>2.2-beta-5</version></plugin><plugin><artifactId>maven-dependency-plugin</artifactId><version>2.8</version></plugin><plugin><artifactId>maven-release-plugin</artifactId><version>2.5.3</version></plugin></plugins></pluginManagement></build>這里依次定義了項目的主輸出目錄,主代碼輸出目錄等等各個參數設定
反應堆
在一個多模塊的Maven項目中,反應堆(Reactor)是指所有模塊組成的一個構建結構,對于單模塊的項目,反應堆就是其本身,但對于多模塊項目來說,反應堆就包含了各個模塊之間繼承和依賴的關系,從而能夠自動計算出合理的模塊構建順序。
反應堆的構建順序
將account-aggregator包含
<module>account-email</module> <module>account-persist</module> <module>account-parent</module>構建輸出:
上述可以看出反應堆,依次是aggregator,parent,email,persist,結果中看到parent跑到了email之前,這是因為考慮到了繼承和依賴關系,因為email和persist都依賴于parent,所有parent就必須先于另外兩個模塊構建,如果出現A依賴于B,而B也依賴于A時,Maven就會報錯。
裁剪反應堆
用戶想要僅僅構建完整反應堆中的某些個模塊,Maven提供很多的命令行選項支持裁剪反應堆,輸入mvn -h可以看到這些選項:
-am,--also-make(同時構建所列模塊的依賴模塊),
 -amd, -also-make-dependents(同時構建依賴于所列模塊的模塊)
 -pl, --projects<arg>(構建指定的模塊,模塊間用逗號分隔)
 -rf -resume-from<arg>(從指定的模塊回復反應堆)
默認情況從account-aggregator執行 mvn clean install
-pl選項指定構建某幾個模塊
mvn clean install -pl account-email,account-persist
使用-am選項可以同時構建所列模塊的依賴模塊
mvn clean install -pl account-email -am。
使用-amd選項可以同時構建依賴于所列模塊的模塊。account-email,account-persist都依賴于account-parent
mvn clean install -pl account-parent -amd
-rf 選項可以在完整的反應堆構建順序基礎上指定從哪個模塊開始構建
mvn clean install -rf account-email
完整的反應堆構建順序中,account-email位于第三,之后只有account-persist,因此只會得到email和persist的反應堆
最有在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參數構建,因此會得到如下反應堆 email和persist:
?
?
總結
以上是生活随笔為你收集整理的Maven(3)--聚合与继承的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Maven(2)--生命周期以及插件目标
- 下一篇: Maven(4)--POM配置
