Maven是一個採用純Java編寫的開源項目管理工具。Maven採用了一種被稱之爲project object model (POM)概念來管理項目,全部的項目配置信息都被定義在一個叫作POM.xml的文件中,經過該文件,Maven能夠管理項目的整個聲明週期,包括編譯,構建,測試,發佈,報告等等。目前Apache下絕大多數項目都已經採用Maven進行管理。而Maven自己還支持多種插件,能夠方便更靈活的控制項目。 java
理解maven的第一步咱們須要知道構建是什麼?《maven實戰》這本書裏寫的很清楚,早上咱們會從代碼庫裏簽出最新的代碼,而後進行單元測試,若是發現bug就會找同事一塊兒解決,以後回到本身的工做上,編寫單元測試或者產品代碼,而後測試,午餐後可能會須要開個會,彙報工做進度,查看測試報告那麼就須要用IDE使用相關的工具集成,生成報告給經理查看,也可能QA發來了幾個bug,因而熟練地用IDE生成了一個WAR包,部署到Web容器下,啓動容器。看到熟悉的界面了,遵循bug報告,一步步重現了bug。。。修改好bug,提交代碼,通知QA,下班。就會發現,在一天的工做中,咱們出了編寫代碼就是在編譯,運行生成文檔,打包和部署等煩瑣且不起眼的工做上,這就是構建。若是手工這樣作,那成本也過高了,因而有人用軟件的方法讓這一系列工做徹底自動化,使得軟件的構建能夠像全自動流水線同樣,只須要一條簡單的命令,全部煩瑣的步驟都可以自動完成,很快就能獲得最終結果。程序員
Maven的用途之一是服務於構建,它是一個異常強大的構建工具,可以幫咱們自動化構建過程,從清理、編譯、測試到生成報告,再到打包和部署。咱們要作的是使用Maven配置好項目,而後輸入簡單的命令(如mvn clean install),Maven會幫咱們處理那些煩瑣的任務。Maven是跨平臺的,不管是在Windows上,仍是在Linux或者Mac上,均可以使用一樣的命令。maven 能最大化的消除重複的構建,咱們不須要去定義繁瑣的構建過程,只要在maven裏配置好相關的信息就好。最簡單的例子是測試,咱們不必告訴Maven去測試,更不須要告訴Maven如何運行測試,只須要遵循Maven的約定編寫好測試用例,當咱們運行構建的時候,這些測試便會自動運行。maven能夠幫助標準化構建過程,有了Maven以後,全部項目的構建命令都是簡單一致的,這極大地避免了沒必要要的學習成本,並且有利於促進項目團隊的標準化。Maven做爲一個構建工具,不只能幫咱們自動化構建,還可以抽象構建過程,提供構建任務實現;它跨平臺,對外提供了一致的操做接口,這一切足以使它成爲優秀的、流行的構建工具。web
maven不只僅是一個構建工具,他仍是一個依賴管理工具和項目信息管理工具,它提供了中央倉庫,能夠幫咱們自動的下載構件。好比在使用javaweb開發是,會用到各類的第三方的庫或者框架,這些類庫均可以經過依賴的方式注入到項目中,隨着依賴的增多,版本的不一致,版本的兼容性,臃腫的問題就會出現。每次手工的解決這些問題會很煩躁,maven就提供了一個優秀的解決方案,它經過一個座標系統準確地定位每個構件(artifact),也就是經過一組座標Maven可以找到任何一個Java類庫(如jar文件)。Maven給這個類庫世界引入了經緯,讓它們變得有秩序,因而咱們能夠藉助它來有序地管理依賴,輕鬆地解決那些繁雜的依賴問題。算法
Maven還能幫助咱們管理本來分散在項目中各個角落的項目信息,包括項目描述、開發者列表、版本控制系統地址、許可證、缺陷管理系統地址等。這些微小的變化看起來很瑣碎,並不起眼,但卻在不知不覺中爲咱們節省了大量尋找信息的時間。除了直接的項目信息,經過Maven自動生成的站點,以及一些已有的插件,咱們還可以輕鬆得到項目文檔、測試報告、靜態分析報告、源碼版本日誌報告等很是具備價值的項目信息。spring
maven與IDE的比較:apache
IDE雖然提升了編碼的效率,但編程
IDE依賴大量的手工操做。編譯、測試、代碼生成等工做都是相互獨立的,很難一鍵完成全部工做。手工勞動每每意味着低效,意味着容易出錯。設計模式
很難在項目中統一全部的IDE配置,每一個人都有本身的喜愛。也正是因爲這個緣由,一個在機器A上能夠成功運行的任務,到了機器B的IDE中可能就會失敗。api
咱們應該合理利用IDE,而不是過多地依賴它。對於構建這樣的任務,在IDE中一次次地點擊鼠標是愚蠢的行爲。Maven是這方面的專家,並且主流IDE都集成了Maven,咱們能夠在IDE中方便地運行Maven執行構建。網絡
maven於ant的區別:
ant意指「另外一個整潔的工具」(Another Neat Tool),它最先用來構建著名的Tomcat。能夠將Ant當作是一個Java版本的Make,也正由於使用了Java,Ant是跨平臺的。此外,Ant使用XML定義構建腳本build.xml。Ant是沒有依賴管理的,因此很長一段時間Ant用戶都不得不手工管理依賴,如今能夠藉助Ivy管理依賴。而Maven內置了依賴管理。
使用maven的狀況:
好比你是一個小軟件公司的程序員,他所在的公司要開發一個新的Web項目。通過協商,決定使用Spring、iBatis和Tapstry。jar包去哪裏找呢?公司裏估計沒有人能把Spring、iBatis和Tapstry所使用的jar包一個很多地找出來。你們的作法是,先到Spring的站點上去找一個spring.with.dependencies,而後去iBatis的網站上把全部列出來的jar包下載下來,對Tapstry、Apache commons等執行一樣的操做。項目尚未開始,WEB.INF/lib下已經有近百個jar包了,帶版本號的、不帶版本號的、有用的、沒用的、相沖突的,怎一個「亂」字了得! 在項目開發過程當中,不時地會發現版本錯誤和版本衝突問題,這時只能硬着頭皮逐一解決。項目開發到一半,經理髮現最終部署的應用的體積實在太大了,要求去掉一些沒用的jar包,因而只能加班加點地一個個刪…… 這時就會想,要是能有一個系統或者框架來管理這些依賴就行了, 這時maven就發揮到做用了。
書籍看到這裏,讓我想起大四的時候進來實驗室時的一個項目,就是基於SSH框架的某公司管理系統,當時,在搭建環境的時候就須要一天的時候(網絡卡),到不一樣的網站去下不一樣的jar包,和安裝不一樣的框架,期間出錯了幾回,爲了不在次出錯本身就手動的備份了全部資料,單獨列了一個清單,記錄各個依賴的版本。如今回過頭來看,若是當時師兄師姐使用這個來構建項目的話,會有多輕鬆啊。實驗室所學到的東西確實是有限的,不少新技術沒有跟不上社會的變化。
maven與極限編程:
maven能很好的使用極限編程XP的一些實踐當中去
測試驅動開發(TDD)。TDD強調測試先行,全部產品都應該由測試用例覆蓋。而測試是Maven生命週期的最重要的組成部分之一,而且Maven有現成的成熟插件支持業界流行的測試框架,如JUnit和TestNG。
十分鐘構建。十分鐘構建強調咱們可以隨時快速地從源碼構建出最終的產品。這正是Maven所擅長的,只須要一些配置,以後用一條簡單的命令就能讓Maven幫你清理、編譯、測試、打包、部署,而後獲得最終的產品。
持續集成(CI)。CI強調項目以很短的週期(如15分鐘)集成最新的代碼。實際上,CI的前提是源碼管理系統和構建系統。
在傳統的瀑布模型開發中,項目依次要經歷需求開發、分析、設計、編碼、測試和集成發佈階段。從設計和編碼階段開始,就可使用Maven來創建項目的構建系統。在設計階段,也徹底能夠針對設計開發測試用例,而後再編寫代碼來知足這些測試用例。然而,有了自動化構建系統,咱們能夠節省不少手動的測試時間。此外,儘早地使用構建系統集成團隊的代碼,對項目也是百利而無一害。最後,Maven還能幫助咱們快速地發佈項目。
maven安裝:
最新的eclipse中集成的是3.2.1的maven,爲了和命令行一塊兒使用,我在插件裏面使用3.2.5的,本機上安裝的也是3.2.5,這個只要在eclipse裏面設置一下就行了。固然也能夠設置回去的。
maven使用
(一) 生成pom
pom.xml 文件是maven對一個項目的核心配置,這個文件將包含你但願如何構建項目的大多數配置信息,用於描述項目如何構建,聲明項目依賴,等等。
雖然很難列出一張很是全面的表,但在此可先列出最普通的默認的生命週期階段:
validate:驗證工程是否正確,全部須要的資源是否可用。
compile:編譯項目的源代碼。
test:使用合適的單元測試框架來測試已編譯的源代碼。這些測試不須要已打包和佈署。
Package:把已編譯的代碼打包成可發佈的格式,好比jar。
integration-test:若有須要,將包處理和發佈到一個可以進行集成測試的環境。
verify:運行全部檢查,驗證包是否有效且達到質量標準。
install:把包安裝在本地的repository中,能夠被其餘工程做爲依賴來使用。
Deploy:在集成或者發佈環境下執行,將最終版本的包拷貝到遠程的repository,使得其餘的開發者或者工程能夠共享。
clean:清除先前構建的artifacts(在maven中,把由項目生成的包都叫做artifact)。
site:爲項目生成文檔站點。
首先建立一個空文件夾,在改文件夾裏新建一個文佳pom.xml,配置文件,具體內容爲:
<span style="font-size: small;"><?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.silence</groupId> <artifactId>hello-world</artifactId> <version>1.0-SNAPSHOT</version> <name>Maven Hello World Project</name> </project> </span>
第二行:project元素,這是pom.xml的根元素,聲明pom相關的命名空間,這裏面的屬性可讓咱們的IDE跟快速的編輯pom第一行:制定了該xml文檔的版本和編碼方式。
第六行:根元素下的第一個子元素modelVersion指定了當前POM模型的版本,對於Maven2及Maven 3來講,它只能是4.0.0。
第7行到9行是最重要的代碼段,groupId,artifactId和version這三個元素定義了一個項目基本的座標,在Maven的世界,任何的jar、pom或者war都是以基於這些基本的座標進行區分的。
groupId定義了項目屬於哪一個組,這個組每每和項目所在的組織或公司存在關聯,譬如你在googlecode上創建了一個名爲myapp的項目,那麼groupId就應該是com.googlecode.myapp,若是你的公司是mycom,有一個項目爲myapp,那麼groupId就應該是com.mycom.myapp。
artifactId定義了當前Maven項目在組中惟一的ID,咱們爲這個Hello World項目定義artifactId爲hello-world,本書其餘章節代碼會被分配其餘的artifactId。而在前面的groupId爲com.googlecode.myapp的例子中,你可能會爲不一樣的子項目(模塊)分配artifactId,如:myapp-util、myapp-domain、myapp-web等等。
version指定了Hello World項目當前的版本——1.0-SNAPSHOT。SNAPSHOT意爲快照,說明該項目還處於開發中,是不穩定的版本。隨着項目的發展,version會不斷更新,如升級爲1.0、1.1-SNAPSHOT、1.一、2.0等等。
第十行:name元素聲明瞭一個對於用戶更爲友好的項目名稱,雖然這不是必須的,但我仍是推薦爲每一個POM聲明name,以方便信息交流。
(二)編寫主代碼
項目主代碼和測試代碼不一樣,項目的主代碼會被打包到最終的構件中(好比jar),而測試代碼只在運行測試時用到,不會被打包。默認狀況下,Maven假設項目主代碼位於src/main/java目錄,咱們遵循Maven的約定,建立該目錄,而後在該目錄下建立文件com/juvenxu/mvnbook/helloworld/HelloWorld.java,
寫好這個以後,能夠回到項目根目錄下,運行mvn clean compile就能夠生成編譯java文件,生成對應的class文件
(三)測試代碼
Maven項目中默認的測試代碼目錄是src/test/java。com/juvenxu/mvnbook/helloworld/testHelloWorld.java
要有測試代碼得爲Hello World項目添加一個JUnit依賴,即在pom.xml中添加<dependencies>元素;
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> </dependencies>
第6行:scope爲依賴範圍,若依賴範圍爲test則表示該依賴只對測試有效,換句話說,測試代碼中的import JUnit代碼是沒有問題的,可是若是咱們在主代碼中用import JUnit代碼,就會形成編譯錯誤。若是不聲明依賴範圍,那麼默認值就是compile,表示該依賴對主代碼和測試代碼都有效。有了這段聲明,Maven就可以自動從中央倉庫(http://repo1.maven.org/maven2/)裏下載junit-4.7.jar。
(四)執行
mvn clean compile、mvn clean test(測試)、mvn clean package(打包)、mvn clean install(安裝)。執行test以前是會先執行compile的,執行package以前是會先執行test的,而相似地,install以前會執行package。
命令行輸入的是mvn clean test,而maven實際執行的可不止這兩個任務,還有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。暫時咱們須要瞭解的是,在Maven執行測試(test)以前,它會先自動執行項目主資源處理,主代碼編譯,測試資源處理,測試代碼編譯等工做,這是Maven生命週期的一個特性。
(五)簡單的原型Archetype
能夠快速的生成項目骨架,避免每次都一個個的建立文件夾,能夠執行mvn archetype:generate,也能夠在eclipse中選擇。固然也能夠根據本身的須要開發使用自定義的archetype來快速生成項目骨架。
爲了能自動的解析任何一個java構件,maven就將他們用座標惟一標識,座標元素包括:groupId,artifactId,version,packaging,
classifier,只要設置這幾個元素就能夠很輕鬆地從中央倉庫那兒得到對應的構件。前三天上面有介紹過,這裏說說packaging:定義maven的打包方式,通常爲jar(默認),固然也能夠是war行的,最終會生成war的文件。classifier:幫助定義構建輸出的一些附屬構件。如某項目的主構件是nexus-index-2.0.0.jar,可能還會有nexus-index-2.0.0-Javadoc.jar和nexus-index-2.0.0-sources.jar這樣一些附屬構件(java文檔和源代碼),這裏javadoc和sources就是這兩個附屬構件的classifier,這樣附屬的構件也會有本身惟一的座標。
每一個依賴包含的元素有:groupId、artifactId、version還有type:
scope:依賴範圍。用來控制依賴與這三種classpath的關係(編譯classpath、運行classpath、測試classpath),若是沒有指定依賴範圍則默認使用compile,在編譯、運行和測試的時候都須要用到該依賴。test則只對測試classpath有效,在編譯主代碼和運行項目的時候不會包含進去。runtime運行時的依賴,對測試運行有效,在編譯主代碼時無效。其實,還有provided和system兩種。
optional:標記依賴是否可選,好比項目A依賴於項目B,B依賴於X和Y(XY可選的),根基依賴傳遞性,XY會是A的傳遞性依賴,可是因爲XY是可選的,那麼依賴不會傳遞,XY對A不會有影響。也就是說XY只對B起做用,不會被傳遞,若是A中須要XY則須要顯示的聲明。這個並不推薦,最好的方式就是排除依賴。可使用maven命令分析依賴關係:mvn dependency:analyze
exclusions:用來排除傳遞性依賴
maven引人的傳遞性依賴機制。一方面大大簡化和方便了依賴聲明。另外一方面,大部分狀況下咱們只須要關心項目的直接依賴是什麼,而不用考慮這些直接依賴會引人什麼傳遞性依賴。但有時候,當傳遞性依賴形成問題的時候,咱們就須要清楚地知道該傳遞性依賴是從哪條依賴路徑引人的。這個能夠之後遇到了在瞭解。
依賴範圍
就是用來控制依賴與這三種classpath(編譯classpath、測試classpath、運行classpath)的關係,Maven有如下幾種依賴範圍:
compile: 編譯依賴範圍。若是沒有指定,就會默認使用該依賴範圍。使用此依賴範圍的Maven依賴,對於編譯、測試、運行三種classpath都有效。
test: 測試依賴範圍。使用此依賴範圍的Maven依賴,只對於測試classpath有效,在編譯主代碼或者運行項目的使用時將沒法使用此類依賴。典型的例子就是JUnit,它只有在編譯測試代碼及運行測試的時候才須要。
provided: 已提供依賴範圍。使用此依賴範圍的Maven依賴,對於編譯和測試classpath有效,但在運行時無效。典型的例子是servlet-api,編譯和測試項目的時候須要該依賴,但在運行項目的時候,因爲容器已經提供,就不須要Maven重複地引入一遍。
runtime: 運行時依賴範圍。使用此依賴範圍的Maven依賴,對於測試和運行classpath有效,但在編譯主代碼時無效。典型的例子是JDBC驅動實現,項目主代碼的編譯只須要JDK提供的JDBC接口,只有在執行測試或者運行項目的時候才須要實現上述接口的具體JDBC驅動。
system: 系統依賴範圍。該依賴與三種classpath的關係,和provided依賴範圍徹底一致。可是,使用system範圍依賴時必須經過systemPath元素顯式地指定依賴文件的路徑。因爲此類依賴不是經過Maven倉庫解析的,並且每每與本機系統綁定,可能形成構建的不可移植,所以應該謹慎使用。systemPath元素能夠引用環境變量
maven倉庫:
簡單來講就是,maven依賴構件存放的地方,全部的依賴構件都從倉庫裏下載,除了本地的項目依賴。maven有提供一箇中央倉庫,裏面有各類開源的構件,可很方便的從上面得到。固然,這個倉庫是遠程的,也能夠在本地設置一個私服,Nexus就是一個流行的開源maven倉庫管理軟件。如今我只須要使用倉庫裏的就能夠了,不必去創建私服。此處略過。
maven生命週期和插件:
maven的生命週期就是爲了對全部的構建過程進行抽象和統一,從大量項目和構建工具中學習和反思,而後總結了一套高度完善的、易擴展的生命週期。這個生命週期包含了項目的清理、初始化、編譯、測試、打包、集成測試、驗證、部署和站點生成等幾乎全部構建步驟。也就是說,幾乎全部項目的構建,都能映射到這樣一個生命週期上。
在maven的設計中,實際的任務(如編譯源代碼)都交由插件來完成。這種思想與設計模式中的模板方法很是類似。模板方法模式在父類中定義算法的總體結構,子類能夠經過實現或者重寫父類的方法來控制實際的行爲,這樣既保證了算法有足夠的可擴展性,又可以嚴格控制算法的總體結構。
這本書裏寫的很清楚:
public abstract class AbstractBuild{ public void Build(){ initialize(); compile(); test(); packagee(); integrate(); deploy(); } protected abstract void initialize(); protected abstract void compile(); protected abstract void test(); protected abstract void packagee(); protected abstract void integrate(); protected abstract void deploy(); }
生命週期抽象了構建的各個步驟,定義它們的次序,但沒有提供具體實現,那麼誰來實現這些步驟呢?不能有用戶爲了編譯而寫一堆代碼。爲測試又寫一堆代碼,那麼就在重複發明輪子了?maven考慮了,所以設計插件機制。每一個構建步驟均可以綁定一個或者多個插件行爲,而maven爲大多數構建步驟編寫並綁定了默認插件。插件完成具體的任務,是實現着。maven有自動綁定的插件,固然也能夠自定義綁定,在pom中設置build plugins plugin屬性。
maven有三套獨立的生命週期:clean(清理項目)、default(構建項目)、site(創建項目站點)。每一個生命週期都有幾個階段,這些階段是有順序的,調用後面的階段時,必須先調用前面的階段。咱們從命令行執行maven命令就是在調用其生命週期階段,好比:mvn clean:就是執行pre-clean和clean階段。mvn test:執行default週期的validate、initialize……直到test階段。mvn clean install:就是clean階段加上default週期的直到install階段。
maven聚合和繼承:
咱們一般會將不一個項目分紅不一樣的模塊向,註冊服務會分紅persist,service等模塊,maven的聚合特性可以把項日的各個模塊聚合在一塊兒構建,而maven繼承特性則能幫助抽取各模塊相同的依賴和插件等配置。在衆多模塊中,不可能對每一個項目都進行構建,執行maven命令,會想用一個命令就運行幾個模塊的內容,爲了可以一條命令就構建兩個模塊,須要在額外的建立一個account-aggregato模塊,而後經過該模塊構建整個項目的全部模塊。對於聚合模塊來講,pom.xml中的打包方式必須爲pom,不然就沒法構建。各個模塊能夠放在聚合模塊目錄下,即和pom同一個目錄,聚合模塊是項目目錄的最頂層,其餘莫快則做爲其子目錄存在。這個並非惟一的,子模塊也能夠和聚合模塊平行。
多模塊項目中,各模塊中會有不少相同的groupID和version,相同的spring依賴,和plugin配置。這就是重複,重複每每覺得着更
更多的勞動和更多的潛在的問題。在面向對象世界中,程序員可使用類繼承在必定程度上消除重複,在maven的世界中,也有相似的機制能讓咱們抽取出重複的配置,這就是POM的繼承。須要建立POM的斧子結構,而後在父POM中聲明一些配置供子POM繼承。以實現一處聲明,多處使用的目的。
聚合的目的:快速構建項目
繼承的目的:消除重複配置
參考書籍:《maven實戰》 http://hzbook.group.iteye.com/group/wiki/2872-Maven-in-action