一、咱們天天除了編寫源代碼之外,有至關一部分時間花在了編譯、單元測試、生成報告、打包和部署等繁瑣的且不起眼的工做上,這就是構建.maven是一個異常強大的構建工具,能幫咱們自動化構建過程,從清理、編譯、測試到生成報告,再到打包部署.java
二、幾乎全部的Java應用都會用到第三方類庫,隨着類庫的增多,版本不一致,版本衝突,依賴臃腫等問題接踵而來,針對這些問題maven提供了優秀的解決方案,它經過一個座標系統準肯定位每個構建,爲這個類庫世界引入了經緯,咱們能夠藉助它來有序管理依賴.linux
一、首先安裝jdk.
web
二、下載解壓apache-maven-3.0-bin.tar.gz. 命令:算法
tar -xzf apache-maven-3.0-bin.tar.gz
三、推薦在安裝目錄旁平行的建立一個符號連接,方便往後的升級,不用每次都更新環境變量,只需更新符號連接指向新的版本maven便可.命令:spring
ln -s apche-maven-3.0 apache-maven
四、設置maven環境變量 略.數據庫
五、檢查Maven安裝apache
mvn -v
六、設置HTTP代理,若是公司基於安全考慮,須要代理訪問英特網,就須要爲Maven配置HTTP代理,才能訪問外部倉庫,已下載所需資源,編輯M2_HOME/conf/settings.xml中的proxies標籤,略,windows
七、設置MAVEN_OPTS環境變量值爲 - Xms128m - Xmx512m,默認的能夠可用內存每每不能知足maven的須要.設計模式
八、配置用戶範圍的settings.xml,~/.m2下也有一個settings.xml,建議日常修改它,這樣Maven升級時,無需再拷貝它,感受怎麼都行.緩存
九、修改IDE默認的maven,編輯Windows->Perferences->Installation,去掉Embedded Maven,而後Add選擇M2_HOME安裝目錄勾選.
一、編寫POM(定義項目的基本信息,描述項目如何構建,聲明項目依賴等).
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!-- 指定了當前POM模型的版本,對於Maven2及Maven3來講,它只能是4.0.0 -->
<modelVersion>4.0.0</modelVersion>
<!-- 最重要的三項, groupId, artifactId,version定義了一個項目的基本座標 -->
<!-- 定義項目屬於哪一個組,好比org.springframework -->
<groupId>com.wangwei</groupId>
<!-- 定義了當前項目在上面那個組中的惟一ID(一個組下面能夠有多個項目) -->
<artifactId>hello-world</artifactId>
<!-- 當前項目的版本,好比此處的1.0的快照版本,快照指項目還處於開發中,並不穩定 -->
<version>1.0-SNAPSHOT</version>
<!--聲明瞭一個對於用戶更爲友好的項目名稱,雖然這不是必須的 -->
<name>Maven Hello World Project</name>
</project>
二、編寫主代碼
1>項目的最代碼會被打包到最終的jar中,而測試代碼只在測試時用到,不會被打包,主代碼位於src/main/java目錄,咱們遵循約定在該目錄下建立文件com/wangwei/helloworld/HelloWorld.java,程序打印一個字符串,這裏注意通常來講Java類的包名應該基於項目的groupId和artifactId,這樣清晰複合邏輯,方便找Java類.
2>運行mvn clean compile進行編譯,clean清理輸出目錄target/,compile編譯項目主代碼.
三、編寫測試代碼
1>修改POM以下:
<?xml version="1.0" encoding="UTF-8"?>
<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.wangwei</groupId>
<artifactId>hello-world</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Maven Hello World Project</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
有了這段聲明,Maven就能自動從中央倉庫下載junit-4.7.jar,scope爲依賴範圍,test表示只對測試有效,主代碼中import junit會報錯,不聲明scope默認是compile,對主代碼測試代碼都有效.
2>Maven項目默認的測試代碼目錄src/test/java,在該目錄下建立HelloWorld打印一段話,約定測試類都已Test結尾,方法都已test開頭.
3>執行mvn clean test命令,maven實際執行的不止這倆個任務,還有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile,也就是在test執行以前會自動執行項目主資源處理,主代碼編譯,測試資源處理,測試代碼編譯等工做,這是maven生命週期的特性,後面詳解;從輸出還能夠看到maven從中央倉庫下載了junit-4.7.pom和junit-4.7.jar到本地倉庫(~/.m2/respository)中,共全部maven項目使用;從輸出還看到在執行compiler:testCompile任務失敗了,這是因爲歷史緣由,maven核心插件之一的compiler默認只支持Java 1.3,須要配置支持1.5,代碼以下(也可在settings.xml中進行全局設置):
<project> ... <build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
四、打包和運行
1>HelloWorld中POM中沒有指點打包類型默認是jar,執行mvn clean package進行打包,相似的maven在打包以前會執行編譯,測試等操做,這裏看到jar:jar任務負責打包,實際就是jar插件的jar目標將項目的主代碼打包成一個hello-world-1.0-SNAPSHOT.jar文件,該文件位於target/輸出目錄中,還能夠根據finalName定義該文件的名稱.
2>咱們獲得了項目的輸出,若是有須要的話,就能夠複製這個jar文件到其它項目的ClassPath中從而使用HelloWorld類,可是,其餘項目怎麼直接引用這個jar呢,還須要一個步驟mvn clean install,從輸出能夠看到該任務將輸出的jar安裝到 了maven的本地倉庫中,這樣其餘項目就可以使用了.相似的install以前會執行package.
3>到目前爲止尚未運行項目,HelloWold類有一個main方法,默認打包的jar是不能直接運行的,由於帶有main方法的類信息不會添加到manifest中(jar文件的META-INF/MANIFEST_MF中沒法看到Main-Class一行),爲了生成可執行的jar,須要藉助maven-shade-plugin插件,配置以下(<project><build><plugins>下面):
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com/wangwei/helloworld/HelloWorld.java</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
執行Java -jar target\hello-world-1.0.SNAPSHOT.jar能夠正常看到輸出.
五、Archetype插件能夠根據咱們提供的信息建立項目的骨架,執行mvn archetype:generate便可,實際開發使用IDE建立Archetype.
六、m2eclipse簡單使用,導入maven項目,建立maven項目,運行maven構建,略.
一、簡單依賴配置groupId、artifactId、version、packaging、scope略.
二、傳遞性依賴,例:account-mail中有個spring-core依賴,spring-core裏又有一個commons-logging依賴,那麼commons-logging就是account-mail的一個傳遞性依賴,有傳遞性依賴機制,在使用spring framework的時候就不用考慮它依賴了什麼,也不用擔憂引入多餘的依賴,Maven會解析各個直接的依賴POM,並將那些必要的間接依賴,以傳遞性依賴的形式引入到當前的項目中.
三、依賴調解,maven引入傳遞性依賴機制,大大簡化和方便了依賴聲明,另外一方面咱們只須要關係直接依賴,而不用考慮這些直接依賴會引入什麼傳遞性依賴,可是當傳遞性依賴形成問題的時候,就須要清楚的知道該傳遞性依賴是從那條依賴路徑引入的.例如:A->B->X(1.0);A->X(2.0),兩條路徑上有兩個不一樣版本的X,那麼哪一個X會被maven解析使用呢,Maven依賴調解的第一原則:路徑最近者優先,若是路徑相同,第二原則:第一聲明者優先,也就是在POM中的聲明順序.
四、可選依賴<optional>,例如A->B、B->X(可選)、B->Y(可選),這裏的X、Y就是A的傳遞性依賴,但因爲這裏是可選的,依賴不會傳遞,若是A中要用X和Y時,還須要在A中聲明,這玩意有吊用.
五、排除依賴<exclusions>,好比當前項目A->B->X(SNAPSHOT),X不穩定,這時就須要排除這個傳遞依賴,手動聲明該類庫的正式版,還有些狀況,如A->B->X,X因爲版權的緣由不在中央倉庫,而C->X,C項目有一個對應的實現,就能夠排除B中的X,採用C中的.代碼:
<dependency>
<groupId>org.unitils</groupId>
<artifactId>unitils-testng</artifactId>
<version>${unitils.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>//exclusino能夠有多個
<artifactId>junit</artifactId>
<groupId>junit</groupId>
</exclusion>
</exclusions>
</dependency>
六、使用maven屬性歸類依賴,其實就是把版本一致的抽出來統必定義,例spring framework:
<properties>
<org.springframework.version>3.2.8.RELEASE</org.springframework.version>
</properties>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
一、座標和依賴是任何一個構建在maven世界中的邏輯表示方式;而構建的物理表示方式是文件,maven經過倉庫來統一管理這些文件.
二、何爲maven倉庫,好比咱們一臺服務器有幾十個項目,這些項目都用到了log4j,struts2等jar,在非maven項目中咱們每每能發現lib的目錄,各個項目的lib存在大量的重複,得益於座標機制,maven項目中使用任何一個構建的方式都是徹底相同的,再次基礎上,maven能夠在某個位置統一存儲全部maven項目共享的構建,這個統一的位置就是倉庫,實際的maven項目將不在各自存儲其依賴文件,他們只須要聲明這些依賴的座標,在須要的時候,maven會自動根據座標找到倉庫中的構建,並使用它們.
三、倉庫的佈局,也就是jar存儲路徑與座標的對應關係,以下:groupId/artifactId/version/artifactId-version.packaging.
四、倉庫的分類,本地倉庫和遠程倉庫,maven尋找構建時首先查看本地,有則直接使用,沒有則去遠程倉庫查找,發現就下載到本地倉庫使用,若是遠程也沒有則報錯.中央倉庫是Maven核心自帶的遠程倉庫,私服是另外一種特殊的遠程倉庫,是爲了節省帶寬和時間在局域網內架設的一個私有倉庫服務器,內部的項目還能部署到私服上供其餘項目使用.除了中央倉庫和私服,還有不少公開的遠程倉庫.
本地倉庫
一、本地倉庫默認位置,windows:C:\users\wangwei\.m2\repository,Linux:/home/wangwei/.m2/repository/,linux(.)開頭文件隱藏,ls -a查看,能夠自定義本地倉庫目錄地址,編輯~/.m2/settings.xml,默認settings.xml是不存在的,須要從$M2_HOME/conf/settings.xml複製過去,再進行編輯,建議這麼作,而不是直接修改全局目錄的settings.xml.
二、一個構建只有在本地倉庫中以後,才能被其它maven項目使用,構建進入本地倉庫的兩種方式,一是從遠程倉庫下載,二是將本地項目安裝到本地倉庫,mvn clean install命令將項目的構建輸出安裝到本地倉庫.
三、本地倉庫相似書房只有一個,遠程倉庫相似書店,有不少.
中央倉庫
中央倉庫是一個默認的遠程倉庫,maven的安裝文件自帶了中央倉庫的配置,$M2_HOME/lib/maven-model-builder-3.0.jar中:
<repositories>
<repository>
<id>central</id>
<name> Maven Repository Switchboard</name>
<layout> default</layout>
<url> http://repo1.maven.org/maven2</url>
<snapshots>
<enabled> false</enabled>
</snapshots>
</repository>
</repositories>
私服
一、私服是一種特殊的遠程倉庫,它是架設在局域網內的倉庫服務,私服代理廣域網的遠程倉庫,共局域網的maven用戶使用,當須要下載構件的時候,它會先從私服請求,若是私服不存在,再從遠程下載,緩存在私服上以後,再爲maven的下載提供服務,一些沒法從外部倉庫下載的構件也能從本地上傳到私服上供你們使用.
二、私服的好處:節省本身的網絡帶寬,加速maven構件,部署第三方構件,提升穩定性,下降中央倉庫的負荷.
遠程倉庫的配置
一、有時默認的中央倉庫沒法知足項目的需求,可能在JBoss Maven倉庫,POM中配置該倉庫:
<repositories>
<repository>
<id>jobss</id>
<name>JBoss Repository</name>
<layout>default</layout>
<url>http://repository.jboss.com/maven2/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
對於releases和snapshots來講,除了enabled,還有兩個元素updatePolicy和checksumPolicy,updatePolicy配置遠程倉庫檢查更新的頻率,默認值爲daily(天天一次),還有nerver、always(每次構件都檢查更新)、inteval:X(每隔X分鐘檢查一次);checksumPolicy用來配置maven檢查檢驗和文件的策略,略.
遠程倉庫的認證
大部分遠程倉庫無需認證就能夠訪問,可是有時候出於安全方面的考慮,咱們須要提供一些認證信息才能訪問一些遠程倉庫.配置認證信息和配置倉庫信息不一樣,認證信息必須配置在settings.xml文件中.假設爲一個id爲my-proj的倉庫配置認證信息,編輯settings.xml文件以下:
<settings> ... <servers>
<server>
<id>my-proj</id>//這個id必須和POM中須要認證的repository元素id一致
<username>admin</username>
<password>password</password>
</server> ... </settings>
部署至遠程倉庫
一、私服的一大做用是部署第三方構件,編輯pom.xml,配置distributionManagement:
<distributionManagement>
<repository>
<id>pro-release</id>
<name>Proj Release Repository</name>
<url>http://localhost:8081/nexus/content/repositories/RestBus-Releases</url>
</repository>
<snapshotRepository>
<id>pro-snapshot</id>
<name>Proj Snapshot Repository</name>
<url>http://localhost:8081/nexus/content/repositories/RestBus-Snapshots</url>
</snapshotRepository>
</distributionManagement>
二、往遠程倉庫部署構件的時候,每每須要認證,配置已講,注意id一致便可,配置正確後,運行命令:mvn clean deploy,maven就會將輸出構件部署到私服,若是是快照就部署到快照倉庫,發佈版就部署到發佈版倉庫.
鏡像
一、若是倉庫X能夠提供倉庫Y存儲的全部內容,那麼X就是Y的一個鏡像,例,中央倉庫在中國有鏡像,因爲地理文職的因素,這個鏡像能提供比中央倉庫更快的服務,所以,能夠配置maven使用該鏡像來替代中央倉庫.編輯settings.xml:
<settings> … <mirrors>
<mirror>
<id> maven-net-cn</id>
<name> Maven China Mirror</name>
<url> http://maven.net.cn/content/groups/public/</url>
<mirrorOf>central</mirrorOf>//中央倉庫id
</mirror>
</mirrors> … </settings>
任何對於中央倉庫的請求都會轉發至該鏡像,用戶也能夠用一樣的方式來配置其它倉庫的鏡像.
二、關於鏡像的一個更爲常見的用法是結合私服,因爲私服是代理任何外部公用倉庫的,所以私服就是全部倉庫的鏡像,編輯settings.xml:
<settings> ... <mirrors>
<mirror>
<id>internal-repository</id>
<name>Internal Repository Manager</name>
<url>http://192.168.1.100/maven2</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors> ... </settings>
倉庫搜索服務-也就是如何查找須要的依賴,略.
maven使用中,命令行的輸入就對應了生命週期,maven的生命週期是抽象的,其實際行爲都是插件來完成的.如mvn package命令表示執行默認生命週期階段package,這個任務由maven-jar-plugin完成,生命週期和插件協調工做,密不可分.
何爲生命週期
一、maven生命週期就是對全部構件過程進行抽象和統一,這個生命週期包含了項目的清理、初始化、編譯、測試、打包、驗證、部署、站點生成等幾乎全部的構建過程,也便是說幾乎全部的項目構建,都能映射到這樣一個生命週期上.maven的生命週期是抽象的本生不作任何實際的工做,實際的任務由插件來完成,這種思想與模板方法設計模式類似,這樣既能保證算法有足夠的可擴展性,又能嚴格控制算法的總體結構.
二、每一個構建步驟均可以綁定一個或者多個插件行爲,maven爲大多數構建步驟編寫並綁定了默認插件,例如針對編譯的maven-compiler-plugin,針對測試的mven-surefire-pulgin,雖然大多數時候用戶感受不到他們的存在,若是有特殊須要,能夠配置插件定製構件行爲,甚至本身編寫插件.
三套生命週期
一、maven有三套相互獨立的生命週期,clean、default和site,clean目的是清理項目,default的目的是構建項目,site目的是創建項目站點.每一個生命週期都是相互獨立的,且每一個生命週期都包含一些階段,用戶能夠僅僅調用clean生命週期的某個階段,而不會對其它生命週期產生任何影響,例如,用戶調用default生命週期的compile階段不會觸發clean生命週期的任何階段,反之亦然.
二、clean生命週期包含階段:pre-clean,clean,post-clean;default生命週期含重要階段:validate,initialize,process-sources,compile,process-test-sources,test-compile,test,package,install,deploy;site生命週期包含階段:pre-site,site,post-site,site-deploy.
命令行與生命週期
命令行執行maven任務的最主要方式就是調用maven的生命週期階段,一個生命週期的階段是有先後依賴關係的,例以下經常使用命令:
1>mvn clean,該命令調用clean生命週期的clean階段,實際執行了clean生命週期的pre-clean和clean階段.
2>mvn test,調用default生命週期的test階段,實際執行了default生命週期的validate、initialize直到test全部階段.
3>mvn clean install,調用clean生命週期的clean階段和default生命週期的install階段,實際執行了clean生命週期的pre-clean和clean階段以及default生命週期的validate到install全部階段,這是一個很好的實踐.
插件目標
maven的生命週期和插件相互綁定,用以完成實際的構建任務,實際是生命週期和插件的目標相互綁定,maven的核心分發包只有不到3MB,maven會在須要的時候下載插件.maven有大量的內置綁定,以及基本用不到的自定義綁定,略,知道便可.
插件解析機制
爲了方便使用,maven不須要用戶提供插件座標信息,就能夠解析獲得正確的插件,這是一把雙刃劍,與依賴同樣,插件構建一樣基於座標存儲在maven倉庫中,在須要的時候maven會從本地倉庫尋找插件,若是不存在,則從遠程倉庫查找,找到後下載到本地.同依賴同樣,maven內置了插件遠程倉庫配置:
<pluginRepository>
<id>central</id>
<name>Maven plugin</name>
<url>htpp://repo1.maven.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
當maven用到實際項目中時,須要將項目分紅不一樣的模塊,maven的聚合特性能將項目的各個模塊聚合在一塊兒構建(也就是一次構建兩個項目,而不是到兩個模塊下分別執行mvn命令),而繼承特性能幫助抽取各個模塊相同的依賴和配置,在簡化POM的同時,還能促進各個模塊配置的一致性.
聚合
一、爲了能一條命令就構件account-email和account-persist兩個模塊,咱們須要建立一個額外的account-aggregater模塊,經過這個模塊構建整個項目的全部模塊,聚合模塊僅僅是幫助聚合其它模塊的構建工具,它自己並沒有實際的內容,account-aggregator自己也是個 Maven項目,它的目錄結構和POM以下:
//父子關係
account-aggregator
--pom.xml
--account-email
----src
----pom.xml
--account-persist
----src
----pom.xml
<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>
上述POM的groupId與其它兩個模塊同樣,版本也同樣,artifactId爲本身的,packaging必須爲pom.modules是聚合的核心配置,這裏每一個module的值都是一個當前pom的相對目錄.
二、聚合模塊和其它模塊的目錄結構能夠是父子關係或者平行關係.
account-aggregator
--pom.xml
account-email
--src
--pom.xml
account-persist
--src
--pom.xml
聚合模塊對應的POM爲:
<modules>
<module>../account-email</module>
<module>../account-captcha</module>
</modules>
三、測試,聚合模塊運行mvn clean install,能夠看到maven解析聚合模塊的POM,分析要構建的模塊,並計算一個反應堆的構建順序,而後根據這個順序依次構建各個模塊.
繼承
一、多模塊maven項目還有一個問題,那就是多個模塊的POM有不少相同的配置,maven有繼承的機制,讓咱們抽取重複的配置.
二、在account-aggregator下建立一個名爲account-parent的除account-aggregator以外的全部模塊的父模塊,它的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>Maven Account-Parent Project</name>
</project>
這個POM使用了和其它模塊一致的groupId和version,artifactId爲本身的,它的packaging也必須爲pom,因爲它只是爲了幫助消除重複配置,自己也沒有實際內容,有了父模塊,account-email的POM修改以下:
<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>Maven Account-Email Project</name>
<dependencies> ... </dependencies>
<build>
<plugins> ... </plugins>
</build>
</project>
這個POM沒有聲明groupId和version,實際是從父模塊繼承了這兩個元素,這就消除了一些重複的配置,同理account-persist也這麼配置,最後還須要將account-parent加入到account-aggregator:
<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-parent</module>
<module>account-email</module>
<module>account-persist</module>
</modules>
</project>
三、除了上面groupId和version能夠被繼承,依賴也是能夠被繼承的,兩個子模塊中都有的spring,junit的依賴等,能夠將這些放到父模塊中,簡化配置,可是有個問題,如今的這兩個模塊是須要spring這些依賴的,可是之後新加的子模塊就不必定須要這個依賴,那也讓它強制加這些依賴是不合理的,Maven提供的dependencyManagement元素既能讓子模塊繼承到父模塊的依賴配置,又能保證子模塊依賴使用的靈活性,在dependencyManagement元素下的依賴聲明不會引入實際的依賴,不過它可以約束dependencies下的依賴使用,如在account-parent中加入dependencyManagement配置:
<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>Maven Account-Parent Project</name>
<properties>
<springframework.version>2.5.6</springframework.version>
<junit.version>4.10</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>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
繼承了dependencyManagement的account-email的POM:
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.juvenxu.mvnbook.account</groupId>
<artifactId>account-parent</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>account-email</artifactId>
<name>Maven Account-Email Project</name>
<properties>
<javax.mail.version>1.4.1</javax.mail.version>
<greenmail.version>1.3.1b</greenmail.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</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>com.icegreen</groupId>
<artifactId>greenmail</artifactId>
<version>${greenmail.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
上述POM中的依賴配置只有groupId和artifactI的,省去了version,junit還省去了scope,彷佛沒有減小太多的配置,但仍是強烈建議這麼作,dependencyManagement中統一項目依賴的版本,這樣不會發生多個子模塊使用依賴版本不一致的狀況,下降依賴衝突的記概率.ps:一、若是子模塊不聲明依賴的使用,則dependencyManagement中聲明的依賴也不會引入.二、<scope>import<scope> 略.
四、相似的maven也提供了pluginManagement元素管理插件,該元素中配置的依賴不會形成實際的插件調用行爲,當子模塊POM中配置了真正的plugin元素,而且其groupId和artifactId與pluginManagement中配置的插件一致時,pluginManagement的配置纔會被繼承到子模塊,以下:
<build>
<!-- 插件 -->
<pluginManagement>
<plugins>
<!-- 支持java 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<!-- 使用UTF-8編碼處理資源文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
繼承了pluginManagement後的插件子模塊配置:
<build>
<plugins>
<!-- 繼承父pom -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
</plugins>
</build>
能夠將全部用到的插件的版本在父模塊中的pluginManagement中聲明,子模塊使用插件時再也不配置版本信息,這麼作能夠統一項目的插件版本,避免插件不一致或者不穩定問題,更易於維護.
五、聚合和繼承的關係
實際項目中,一個POM可能既是聚合POM又是父POM,這麼作是爲了方便,例將account-aggregator和account-parent合併一個,以下:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<modules>
<module>account-email</module>
<module>account-persist</module>
<module>account-captcha</module>
<module>account-service</module>
<module>account-web</module>
</modules>
<!-- Maven屬性 -->
<properties>
<springframework.version>2.5.6</springframework.version>
<junit.version>4.10</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>
<!-- 支持java 5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<!-- 使用UTF-8編碼處理資源文件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
六、反應堆
1>對於多模塊maven項目中,反應堆是指全部模塊組成的一個構建結構,反應堆包含了各模塊間的繼承和依賴關係,從而能自動計算出合理的模塊構建順序.
2>反應堆的構建順序,構建account-aggregator->account-parent->account-email->account-persist.
3>裁剪反應堆,略.