感謝無知者雲的博客,寫的很好的Maven提升篇的文章html
http://www.davenkin.me/post/2013-08-03/create-multi-module-maven-project前端
一般來講,在Maven的多模塊工程中,都存在一個pom類型的工程做爲根模塊,該工程只包含一個pom.xml文件,在該文件中以模塊(module)的形式聲明它所包含的子模塊,即多模塊工程。在子模塊的pom.xml文件中,又以parent的形式聲明其所屬的父模塊,即繼承。然而,這兩種聲明並沒必要同時存在,咱們將在下文中講到這其中的區別。
web
(一)建立Maven多模塊工程apache
多模塊的好處是你只需在根模塊中執行Maven命令,Maven會分別在各個子模塊中執行該命令,執行順序經過Maven的Reactor機制決定。先來看建立Maven多模塊工程的常規方法。在咱們的示例工程中,存在一個父工程,它包含了兩個子工程(模塊),一個core模塊,一個webapp模塊,webapp模塊依賴於core模塊。這是一種很常見的工程劃分方式,即core模塊中包含了某個領域的核心業務邏輯,webapp模塊經過調用core模塊中服務類來建立前端網站。這樣將核心業務邏輯和前端展示分離開來,若是以後決定開發另外一套桌面應用程序,那麼core模塊是能夠重用在桌面程序中。app
首先經過Maven的Archetype插件建立一個父工程,即一個pom類型的Maven工程,其中只包含一個pom.xml文件:webapp
mvn archetype:generate -DgroupId=me.davenkin -DartifactId=maven-multi-module -DarchetypeGroupId=org.codehaus.mojo.archetypes -DarchetypeArtifactId=pom-root -DinteractiveMode=falsemaven
以上命令在當前目錄下建立了一個名爲maven-multi-module的目錄,該目錄便表示這個pom類型的父工程,在該目錄只有一個pom.xml文件:post
<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/xsd/maven-4.0.0.xsd">ui
<modelVersion>4.0.0</modelVersion>
<groupId>me.davenkin</groupId>
<artifactId>maven-multi-module</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>maven-multi-module</name>
</project>
這個pom.xml很是簡單,最值得一看的是其中的「<packaging>pom</packaging>」,表示該工程爲pom類型。其餘的Maven工程類型還有jar、war、ear等。
此時,父工程便建立好了,接下來咱們建立core模塊,因爲core模塊屬於maven-multi-module模塊,咱們將工做目錄切換到maven-multi-module目錄下(固然你也能夠不用,只是須要一些額外的配置),建立core模塊命令以下:
mvn archetype:generate -DgroupId=me.davenkin -DartifactId=core -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
這裏咱們使用了Archetype插件的maven-archetype-quickstart,它建立一個jar類型的模塊。此時,若是咱們在打開maven-multi-module模塊的pom.xml會發現,其中多瞭如下內容:
<modules>
<module>core</module>
</modules>
這裏的core便是咱們剛纔建立的core模塊,再看看core模塊中的pom.xml文件:
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>maven-multi-module</artifactId>
<groupId>me.davenkin</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>me.davenkin</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
<name>core</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
請注意裏面的 「<parent>... </parent>」,它將maven-multi-module模塊作爲了本身的父模塊。這裏咱們看出,當建立core模塊時,Maven將自動識別出已經存在的maven-multi-module父模塊,而後分別建立兩個方向的指引關係,即在maven-multi-module模塊中將core做爲本身的子模塊,在core模塊中將maven-multi-module做爲本身的父模塊。要使Maven有這樣的自動識別功能,咱們須要在maven-multi-module目錄下建立core模塊(請參考前文),否則,core模塊將是一個獨立的模塊,可是咱們能夠經過手動修改兩個模塊中的pom.xml文件來建立他們之間的父子關係,從而達到一樣的目的。
依然在maven-multi-module目錄下,經過與core相同的方法建立webapp模塊:
mvn archetype:generate -DgroupId=me.davenkin -DartifactId=webapp -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false
這裏的maven-archetype-webapp代表Maven建立的是一個war類型的工程模塊。此時再看maven-multi-module模塊的pom.xml文件,其中的<modules>中多了一個webapp模塊:
<modules>
<module>core</module>
<module>webapp</module>
</modules>
而在webapp模塊的pom.xml文件中,也以 「<parent>... </parent>」的方式將maven-multi-module模塊聲明爲本身的父模塊,這些一樣是得益於Maven自動識別的結果。
此時,在maven-multi-module目錄下,咱們執行如下命令完成整個工程的編譯、打包和安裝到本地Maven Repository的過程:
mvn clean install
(二)手動添加子模塊之間的依賴關係
此時咱們雖然建立了一個多模塊的Maven工程,可是有兩個問題咱們依然沒有解決:
(1)沒有發揮Maven父模塊的真正做用
(2)webapp模塊對core模塊的依賴關係還沒有創建
針對(1),Maven父模塊的做用原本是使子模塊能夠繼承並覆蓋父模塊中的配置,好比dependency等,可是若是咱們看看webapp和core模塊中pom.xml文件,他們都聲明瞭對Junit的依賴,而若是多個子模塊都依賴於相同的類庫,咱們應該將這些依賴配置在父模塊中,繼承自父模塊的子模塊將自動得到這些依賴。因此接下來咱們要作的即是:將webapp和core模塊對junit的依賴刪除,並將其遷移到父模塊中。
對於(2),Maven在建立webapp模塊時並不知道webapp依賴於core,因此這種依賴關係須要咱們手動加入,在webapp模塊的pom.xml中加入對core模塊的依賴:
<dependency>
<groupId>me.davenkin</groupId>
<artifactId>core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
此時再在maven-multi-module目錄下執行 「mvn clean install」,Maven將根據本身的Reactor機制決定哪一個模塊應該先執行,哪一個模塊應該後執行。好比,這裏的webapp模塊依賴於core模塊,那麼Maven會先在core模塊上執行「mvn clean install」,再在webapp模塊上執行相同的命令。在webapp上執行「mvn clean install」時,因爲core模塊已經被安裝到了本地的Repository中,webapp即可以順利地找到所依賴的core模塊。
總的來看,此時命令的執行順序爲maven-multi-module -> core -> webapp,先在maven-multi-module上執行是由於其餘兩個模塊都將它做爲父模塊,即對它存在依賴關係,又因爲core被webapp依賴,因此接下來在core上執行命令,最後在webapp上執行。
這裏又有一個問題:爲何非得在maven-multi-module目錄下執行 「mvn clean install」?答案是,並非非得如此,只是你須要搞清楚Maven的工做機制。在maven-multi-module目錄下執行,便是在父工程中執行,此時Maven知道父模塊所包含的全部子模塊,並會自動按照模塊依賴關係處理執行順序。若是隻在子模塊中執行,那麼Maven並不知道它對其餘模塊的依賴關係。舉個例子,當在webapp中執行 「mvn clean install」,Maven發現webapp本身依賴於core,此時Maven只會在本地的Repository中去找core,若是存在,那麼你很幸運,若是不存在,那麼對不起,運行失敗,說找不到core,由於Maven並不會先將core模塊安裝到本地Repository。此時你須要作的是,切換到core目錄,執行「mvn clean install」將core模塊安裝到本地Repository,再切換回webapp目錄,執行「mvn clean install」,萬事才大吉。
多麼繁瑣的步驟,此時你應該能體會到在maven-multi-module下執行Maven命令的好處了吧。總結一下:在maven-multi-module下執行「mvn clean install」, Maven會在每一個模塊上執行該命令,而後又發現webapp依賴於core,此時他們之間有一個協調者(即父工程),它知道將core做爲webapp的依賴,因而會先在core模塊上執行「mvn clean install」,當在webapp上執行命令時,不管此時的core模塊是否存在於本地Repository中,父工程都可以獲取到core模塊(若是不存在於本地Repository,它將現場編譯core模塊,再將其作爲webapp的依賴,好比此時使用「mvn clean package」也是可以構建成功的),因此一切成功。
這裏又牽扯到Maven如何查找依賴的問題,簡單來講,Maven會先在本地Repository中查找依賴,若是依賴存在,則使用該依賴,若是不存在,則經過pom.xml中的Repository配置從遠程下載依賴到本地Repository中。默認狀況下,Maven將使用Maven Central Repository做爲遠端Repository。因而你又有問題了:「在pom.xml中爲何沒有看到這樣的配置信息啊?」緣由在於,任何一個Maven工程都默認地繼承自一個Super POM,Repository的配置信息便包含在其中。
(三)多模塊 vs 繼承
在文章一開始咱們便提到,在Maven中,由多模塊(由上到下)和繼承(由下到上)關係並沒必要同時存在。
(1)若是保留webapp和core中對maven-multi-module的父關係聲明,即保留 「<parent>... </parent>」,而刪除maven-multi-module中的子模塊聲明,即「<modules>...<modules>」,會發生什麼狀況?此時,整個工程已經不是一個多模塊工程,而只是具備父子關係的多個工程集合。若是咱們在maven-multi-module目錄下執行「mvn clean install」,Maven只會在maven-multi-module自己上執行該命令,繼而只會將maven-multi-module安裝到本地Repository中,而不會在webapp和core模塊上執行該命令,由於Maven根本就不知道這兩個子模塊的存在。另外,若是咱們在webapp目錄下執行相同的命令,因爲由子到父的關係還存在,Maven會在本地的Repository中找到maven-multi-module的pom.xml文件和對core的依賴(固然前提是他們存在於本地的Repository中),而後順利執行該命令。
這時,若是咱們要發佈webapp,那麼咱們須要先在maven-multi-module目錄下執行「mvn clean install」將最新的父pom安裝在本地Repository中,再在core目錄下執行相同的命令將最新的core模塊安裝在本地Repository中,最後在webapp目錄下執行相同的命令完成最終war包的安裝。麻煩。
(2)若是保留maven-multi-module中的子模塊聲明,而刪除webapp和core中對maven-multi-module的父關係聲明,又會出現什麼狀況呢?此時整個工程只是一個多模塊工程,而沒有父子關係。Maven會正確處理模塊之間的依賴關係,即在webapp模塊上執行Maven命令以前,會先在core模塊上執行該命令,可是因爲core和webapp模塊再也不繼承自maven-multi-module,對於每個依賴,他們都須要本身聲明,好比咱們須要分別在webapp和core的pom.xml文件中聲明對Junit依賴。
綜上,多模塊和父子關係是不一樣的。若是core和webapp只是在邏輯上屬於同一個總工程,那麼咱們徹底能夠只聲明模塊關係,而不用聲明父子關係。若是core和webapp分別處理兩個不一樣的領域,可是它們又共享了不少,好比依賴等,那麼咱們能夠將core和webapp分別繼承自同一個父pom工程,而沒必要屬於同一個工程下的子模塊。