概念
Maven是什麼
Maven 是一個項目管理工具。它負責管理項目開發過程中的幾乎所有的東西。
版本
maven有自己的版本定義和規則
建構
maven支援許多種的應用程式類型,對于每一種支援的應用程式類型都定義好了一組建構規則和工具集。
輸出物管理
maven可以管理項目建構的産物,并将其加入到使用者庫中。這個功能可以用于項目組和其他部門之間的傳遞行為
依賴關系
maven對依賴關系的特性進行細緻的分析和劃分,避免開發過程中的依賴混亂和互相污染行為
文檔和建構結果
maven的site指令支援各種文檔資訊的釋出,包括建構過程的各種輸出,javadoc,産品文檔等。
項目關系
一個大型的項目通常有幾個小項目或者子產品組成,用maven可以很友善地管理
移植性管理
maven可以針對不同的開發場景,輸出不同種類的輸出結果
Maven的生命周期
maven把項目的建構劃分為不同的生命周期(lifecycle)。粗略一點的話,它這個過程(phase)包括:編譯、測試、打包、內建測試、驗證、部署。maven中所有的執行動作(goal)都需要指明自己在這個過程中的執行位置,然後maven執行的時候,就依照過程的發展依次調用這些goal進行各種處理。
這個也是maven的一個基本排程機制。一般來說,位置稍後的過程都會依賴于之前的過程。當然,maven同樣提供了配置檔案,可以依照使用者要求,跳過某些階段。
Maven的标準工程結構
Maven的标準工程結構如下:
|-- pom.xml(maven的核心配置檔案)
|-- src
|-- main
| `-- java
(java源代碼目錄)
| `-- resources(資源檔案目錄)
|-- test
`-- java(單元測試代碼目錄)
|-- target(輸出目錄,所有的輸出物都存放在這個目錄下)
|--classes(編譯後的class檔案存放處)
Maven的"約定優于配置"
所謂的"約定優于配置",在maven中并不是完全不可以修改的,他們隻是一些配置的預設值而已。但是除非必要,并不需要去修改那些約定内容。maven預設的檔案存放結構如下:
每一個階段的任務都知道怎麼正确完成自己的工作,比如compile任務就知道從src/main/java下編譯所有的java檔案,并把它的輸出class檔案存放到target/classes中。
對maven來說,采用"約定優于配置"的政策可以減少修改配置的工作量,也可以降低學習成本,更重要的是,給項目引入了統一的規範。
Maven的版本規範
maven使用如下幾個要素來唯一定位某一個輸出物:
groudId
團體、組織的辨別符。團體辨別的約定是,它以建立這個項目的組織名稱的逆向域名(reverse domain name)開頭。一般對應着JAVA的包的結構。例如org.apache
artifactId
單獨項目的唯一辨別符。比如我們的tomcat, commons等。不要在artifactId中包含點号(.)。
version
一個項目的特定版本。
packaging
項目的類型,預設是jar,描述了項目打包後的輸出。類型為jar的項目産生一個JAR檔案,類型為war的項目産生一個web應用。
maven有自己的版本規範,一般是如下定義 <major version>.<minor version>.<incremental version>-<qualifier> ,比如1.2.3-beta-01。要說明的是,maven自己判斷版本的算法是major,minor,incremental部分用數字比較,qualifier部分用字元串比較,是以要小心 alpha-2和alpha-15的比較關系,最好用 alpha-02的格式。
maven在版本管理時候可以使用幾個特殊的字元串 SNAPSHOT,LATEST,RELEASE。比如"1.0-SNAPSHOT"。各個部分的含義和處理邏輯如下說明:
SNAPSHOT
這個版本一般用于開發過程中,表示不穩定的版本。
LATEST
指某個特定構件的最新釋出,這個釋出可能是一個釋出版,也可能是一個snapshot版,具體看哪個時間最後。
RELEASE
指最後一個釋出版。
安裝
官網下載下傳位址
http://maven.apache.org/download.cgi配置環境變量
注意:安裝maven之前,必須先確定你的機器中已經安裝了JDK。
1.解壓壓縮包(以apache-maven-3.3.9-bin.zip為例)
2.添加環境變量MAVEN_HOME,值為apache-maven-3.3.9的安裝路徑

3.在Path環境變量的變量值末尾添加%MAVEN_HOME%\bin
4.在cmd輸入mvn –version,如果出現maven的版本資訊,說明配置成功。
本地倉儲配置
從中央倉庫下載下傳的jar包,都會統一存放到本地倉庫中。我們需要配置本地倉庫的位置。
打開maven安裝目錄,打開conf目錄下的setting.xml檔案。
可以參照下圖配置本地倉儲位置。
第一個Maven工程
在Eclipse中建立Maven工程
Maven插件
在Eclipse中建立Maven工程,需要安裝Maven插件。
一般較新版本的Eclipse都會帶有Maven插件,如果你的Eclipse中已經有Maven插件,可以跳過這一步驟。
點選Help -> Eclipse Marketplace,搜尋maven關鍵字,選擇安裝紅框對應的Maven插件。
Maven環境配置
點選Window -> Preferences
如下圖所示,配置settings.xml檔案的位置
建立Maven工程
File -> New -> Maven Project -> Next,在接下來的視窗中會看到一大堆的項目模闆,選擇合适的模闆。
接下來設定項目的參數,如下:
groupId是項目組織唯一的辨別符,實際對應JAVA的包的結構,是main目錄裡java的目錄結構。
artifactId就是項目的唯一的辨別符,實際對應項目的名稱,就是項目根目錄的名稱。
點選Finish,Eclipse會建立一個Maven工程。
使用Maven進行建構
Eclipse中建構方式
在Elipse項目上右擊 -> Run As 就能看到很多Maven操作。這些操作和maven指令是等效的。例如Maven clean,等同于mvn clean指令。
你也可以點選Maven build,輸入組合指令,并儲存下來。如下圖:
Maven指令建構方式
當然,你也可以直接使用maven指令進行建構。
進入工程所在目錄,輸入maven指令就可以了。
如下圖
使用指導
如何添加外部依賴jar包
在Maven工程中添加依賴jar包,很簡單,隻要在POM檔案中引入對應的<dependency>标簽即可。
參考下例:
<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"> <modelVersion>4.0.0</modelVersion> <groupId>com.zp.maven</groupId> <artifactId>MavenDemo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>MavenDemo</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <junit.version>3.8.1</junit.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> <scope>compile</scope> </dependencies> </project> |
<dependency>标簽最常用的四個屬性标簽:
groupId:項目組織唯一的辨別符,實際對應JAVA的包的結構。
artifactId:項目唯一的辨別符,實際對應項目的名稱,就是項目根目錄的名稱。
version:jar包的版本号。可以直接填版本數字,也可以在properties标簽中設定屬性值。
scope:jar包的作用範圍。可以填寫compile、runtime、test、system和provided。用來在編譯、測試等場景下選擇對應的classpath。
如何尋找jar包
可以在
http://mvnrepository.com/站點搜尋你想要的jar包版本
例如,想要使用log4j,可以找到需要的版本号,然後拷貝對應的maven标簽資訊,将其添加到pom .xml檔案中。
如何使用Maven插件(Plugin)
要添加Maven插件,可以在pom.xml檔案中添加<plugin>标簽。
<configuration>标簽用來配置插件的一些使用參數。
如何一次編譯多個工程
在Maven中,允許一個Maven Project中有多個Maven Module
1.建立maven父工程步驟:new-->other-->選擇maven project-->next-->勾選create a simple project-->next-->填寫Group Id、Artifact Id、Version --> packaging選擇pom-->finish。
2.建立maven子工程步驟:選中剛才建立的父工程右鍵-->new-->other-->選擇maven module-->next-->勾選create a simple project-->填寫module name(其實就是artifact id)-->next-->GAV繼承父工程-->packaging選擇你需要的-->finish。
3.完成,重新整理父工程;如有多個子工程,繼續按照第二步驟建立。
這時打開XXX中的pom.xml可以看到其中有以下标簽
<modules>
<module>xxx1</module>
</modules>
選擇編譯XXX時,會依次對它的所有Module執行相同操作。
常用Maven插件
maven-antrun-plugin
http://maven.apache.org/plugins/maven-antrun-plugin/maven-antrun-plugin能讓使用者在Maven項目中運作Ant任務。使用者可以直接在該插件的配置以Ant的方式編寫Target,然後交給該插件的run目标去執行。在一些由Ant往Maven遷移的項目中,該插件尤其有用。此外當你發現需要編寫一些自定義程度很高的任務,同時又覺得Maven不夠靈活時,也可以以Ant的方式實作之。maven-antrun-plugin的run目标通常與生命周期綁定運作。
maven-archetype-plugin
http://maven.apache.org/archetype/maven-archetype-plugin/Archtype指項目的骨架,Maven初學者最開始執行的Maven指令可能就是mvn archetype:generate,這實際上就是讓maven-archetype-plugin生成一個很簡單的項目骨架,幫助開發者快速上手。可能也有人看到一些文檔寫了mvn archetype:create,但實際上create目标已經被棄用了,取而代之的是generate目标,該目标使用互動式的方式提示使用者輸入必要的資訊以建立項目,體驗更好。
maven-archetype-plugin還有一些其他目标幫助使用者自己定義項目原型,例如你由一個産品需要傳遞給很多客戶進行二次開發,你就可以為他們提供一個Archtype,幫助他們快速上手。
maven-assembly-plugin
http://maven.apache.org/plugins/maven-assembly-plugin/maven-assembly-plugin的用途是制作項目分發包,該分發包可能包含了項目的可執行檔案、源代碼、readme、平台腳本等等。
maven-assembly-plugin支援各種主流的格式如zip、tar.gz、jar和war等,具體打包哪些檔案是高度可控的,例如使用者可以按檔案級别的粒度、檔案集級别的粒度、子產品級别的粒度、以及依賴級别的粒度控制打包,此外,包含和排除配置也是支援的。maven-assembly-
plugin要求使用者使用一個名為
assembly.xml
的中繼資料檔案來表述打包,它的single目标可以直接在指令行調用,也可以被綁定至生命周期。
maven-dependency-plugin
http://maven.apache.org/plugins/maven-dependency-plugin/maven-dependency-plugin最大的用途是幫助分析項目依賴,dependency:list能夠列出項目最終解析到的依賴清單,dependency:tree能進一步的描繪項目依賴樹,dependency:analyze可以告訴你項目依賴潛在的問題,如果你有直接使用到的卻未聲明的依賴,該目标就會發出警告。maven-dependency-plugin還有很多目标幫助你操作依賴檔案,例如dependency:copy-dependencies能将項目依賴從本地Maven倉庫複制到某個特定的檔案夾下面。
maven-enforcer-plugin
http://maven.apache.org/plugins/maven-enforcer-plugin/在一個稍大一點的組織或團隊中,你無法保證所有成員都熟悉Maven,那他們做一些比較愚蠢的事情就會變得很正常,例如給項目引入了外部的
SNAPSHOT依賴而導緻建構不穩定,使用了一個與大家不一緻的Maven版本而經常抱怨建構出現詭異問題。maven-enforcer-
plugin能夠幫助你避免之類問題,它允許你建立一系列規則強制大家遵守,包括設定Java版本、設定Maven版本、禁止某些依賴、禁止
SNAPSHOT依賴。隻要在一個父POM配置規則,然後讓大家繼承,當規則遭到破壞的時候,Maven就會報錯。除了标準的規則之外,你還可以擴充該插件,編寫自己的規則。maven-enforcer-plugin的enforce目标負責檢查規則,它預設綁定到生命周期的validate階段。
maven-help-plugin
http://maven.apache.org/plugins/maven-help-plugin/maven-help-plugin是一個小巧的輔助工具,最簡單的help:system可以列印所有可用的環境變量和Java系統屬性。help:effective-pom和help:effective-settings最為有用,它們分别列印項目的有效POM和有效settings,有效POM是指合并了所有父POM(包括Super
POM)後的XML,當你不确定POM的某些資訊從何而來時,就可以檢視有效POM。有效settings同理,特别是當你發現自己配置的
settings.xml沒有生效時,就可以用help:effective-settings來驗證。此外,maven-help-plugin的describe目标可以幫助你描述任何一個Maven插件的資訊,還有all-profiles目标和active-profiles目标幫助檢視項目的Profile。
maven-release-plugin
http://maven.apache.org/plugins/maven-release-plugin/maven-release-plugin的用途是幫助自動化項目版本釋出,它依賴于POM中的SCM資訊。release:prepare用來準備版本釋出,具體的工作包括檢查是否有未送出代碼、檢查是否有SNAPSHOT依賴、更新項目的SNAPSHOT版本至RELEASE版本、為項目打标簽等等。release:perform則是簽出标簽中的RELEASE源碼,建構并釋出。版本釋出是非常瑣碎的工作,它涉及了各種檢查,而且由于該工作僅僅是偶爾需要,是以手動操作很容易遺漏一些細節,maven-release-plugin讓該工作變得非常快速簡便,不易出錯。maven-release-plugin的各種目标通常直接在指令行調用,因為版本釋出顯然不是日常建構生命周期的一部分。
maven-resources-plugin
http://maven.apache.org/plugins/maven-resources-plugin/為了使項目結構更為清晰,Maven差別對待Java代碼檔案和資源檔案,maven-compiler-plugin用來編譯Java代碼,maven-resources-plugin則用來處理資源檔案。預設的主資源檔案目錄是
src/main/resources
,很多使用者會需要添加額外的資源檔案目錄,這個時候就可以通過配置maven-resources-plugin來實作。此外,資源檔案過濾也是Maven的一大特性,你可以在資源檔案中使用${propertyName}形式的Maven屬性,然後配置maven-resources-plugin開啟對資源檔案的過濾,之後就可以針對不同環境通過指令行或者Profile傳入屬性的值,以實作更為靈活的建構。
maven-surefire-plugin
http://maven.apache.org/plugins/maven-surefire-plugin/可能是由于曆史的原因,Maven
2/3中用于執行測試的插件不是maven-test-plugin,而是maven-surefire-plugin。其實大部分時間内,隻要你的測試類遵循通用的指令約定(以Test結尾、以TestCase結尾、或者以Test開頭),就幾乎不用知曉該插件的存在。然而在當你想要跳過測試、排除某些測試類、或者使用一些TestNG特性的時候,了解maven-surefire-plugin的一些配置選項就很有用了。例如 mvn test -Dtest=FooTest 這樣一條指令的效果是僅運作FooTest測試類,這是通過控制maven-surefire-plugin的test參數實作的。
build-helper-maven-plugin
http://mojo.codehaus.org/build-helper-maven-plugin/Maven預設隻允許指定一個主Java代碼目錄和一個測試Java代碼目錄,雖然這其實是個應當盡量遵守的約定,但偶爾你還是會希望能夠指定多個源碼目錄(例如為了應對遺留項目),build-helper-maven-plugin的add-source目标就是服務于這個目的,通常它被綁定到預設生命周期的generate-sources階段以添加額外的源碼目錄。需要強調的是,這種做法還是不推薦的,因為它破壞了
Maven的約定,而且可能會遇到其他嚴格遵守約定的插件工具無法正确識别額外的源碼目錄。
build-helper-maven-plugin的另一個非常有用的目标是attach-artifact,使用該目标你可以以classifier的形式選取部分項目檔案生成附屬構件,并同時install到本地倉庫,也可以deploy到遠端倉庫。
exec-maven-plugin
http://mojo.codehaus.org/exec-maven-plugin/exec-maven-plugin很好了解,顧名思義,它能讓你運作任何本地的系統程式,在某些特定情況下,運作一個Maven外部的程式可能就是最簡單的問題解決方案,這就是exec:exec的用途,當然,該插件還允許你配置相關的程式運作參數。除了exec目标之外,exec-maven-plugin還提供了一個java目标,該目标要求你提供一個mainClass參數,然後它能夠利用目前項目的依賴作為classpath,在同一個JVM中運作該mainClass。有時候,為了簡單的示範一個指令行Java程式,你可以在POM中配置好exec-maven-plugin的相關運作參數,然後直接在指令運作mvn exec:java 以檢視運作效果。
jetty-maven-plugin
http://wiki.eclipse.org/Jetty/Feature/Jetty_Maven_Plugin在進行Web開發的時候,打開浏覽器對應用進行手動的測試幾乎是無法避免的,這種測試方法通常就是将項目打包成war檔案,然後部署到Web容器中,再啟動容器進行驗證,這顯然十分耗時。為了幫助開發者節省時間,jetty-maven-plugin應運而生,它完全相容
Maven項目的目錄結構,能夠周期性地檢查源檔案,一旦發現變更後自動更新到内置的Jetty
Web容器中。做一些基本配置後(例如Web應用的contextPath和自動掃描變更的時間間隔),你隻要執行 mvn jetty:run ,然後在IDE中修改代碼,代碼經IDE自動編譯後産生變更,再由jetty-maven-plugin偵測到後更新至Jetty容器,這時你就可以直接測試Web頁面了。需要注意的是,jetty-maven-plugin并不是宿主于Apache或Codehaus的官方插件,是以使用的時候需要額外的配置
settings.xml
的pluginGroups元素,将org.mortbay.jetty這個pluginGroup加入。
versions-maven-plugin
http://mojo.codehaus.org/versions-maven-plugin/很多Maven使用者遇到過這樣一個問題,當項目包含大量子產品的時候,為他們集體更新版本就變成一件煩人的事情,到底有沒有自動化工具能幫助完成這件事情呢?(當然你可以使用sed之類的文本操作工具,不過不在本文讨論範圍)答案是肯定的,versions-maven-
plugin提供了很多目标幫助你管理Maven項目的各種版本資訊。例如最常用的,指令 mvn versions:set -DnewVersion=1.1-SNAPSHOT 就能幫助你把所有子產品的版本更新到1.1-SNAPSHOT。該插件還提供了其他一些很有用的目标,display-dependency-
updates能告訴你項目依賴有哪些可用的更新;類似的display-plugin-updates能告訴你可用的插件更新;然後use-
latest-versions能自動幫你将所有依賴更新到最新版本。最後,如果你對所做的更改滿意,則可以使用 mvn versions:commit 送出,不滿意的話也可以使用 mvn versions:revert 進行撤銷。
更多詳情請參考
https://maven.apache.org/plugins/常用Maven指令
生命周期 | 階段描述 |
mvn validate | 驗證項目是否正确,以及所有為了完整建構必要的資訊是否可用 |
mvn generate-sources | 生成所有需要包含在編譯過程中的源代碼 |
process-sources | 處理源代碼,比如過濾一些值 |
generate-resources | 生成所有需要包含在打包過程中的資源檔案 |
process-resources | 複制并處理資源檔案至目标目錄,準備打包 |
mvn compile | 編譯項目的源代碼 |
process-classes | 後處理編譯生成的檔案,例如對Java類進行位元組碼增強(bytecode enhancement) |
generate-test-sources | 生成所有包含在測試編譯過程中的測試源碼 |
mvn process-test-sources | 處理測試源碼,比如過濾一些值 |
generate-test-resources | 生成測試需要的資源檔案 |
process-test-resources | 複制并處理測試資源檔案至測試目标目錄 |
mvn test-compile | 編譯測試源碼至測試目标目錄 |
mvn test | 使用合适的單元測試架構運作測試。這些測試應該不需要代碼被打包或釋出 |
prepare-package | 在真正的打包之前,執行一些準備打包必要的操作。這通常會産生一個包的展開的處理過的版本(将會在Maven 2.1+中實作) |
mvn package | 将編譯好的代碼打包成可分發的格式,如JAR,WAR,或者EAR |
pre-integration-test | 執行一些在內建測試運作之前需要的動作。如建立內建測試需要的環境 |
integration-test | 如果有必要的話,處理包并釋出至內建測試可以運作的環境 |
post-integration-test | 執行一些在內建測試運作之後需要的動作。如清理內建測試環境。 |
mvn verify | 執行所有檢查,驗證包是有效的,符合品質規範 |
mvn install | 安裝包至本地倉庫,以備本地的其它項目作為依賴使用 |
mvn deploy | 複制最終的包至遠端倉庫,共享給其它開發人員和項目(通常和一次正式的釋出相關) |
使用參數
-Dmaven.test.skip=true: 跳過單元測試(eg: mcn clean package -Dmaven.test.skip=true)
常見問題
dependencies和dependencyManagement,plugins和
pluginManagement
有什麼差別?
dependencyManagement是表示依賴jar包的聲明,即你在項目中的dependencyManagement下聲明了依賴,maven不會加載該依賴,dependencyManagement聲明可以被繼承。
dependencyManagement的一個使用案例是當有父子項目的時候,父項目中可以利用dependencyManagement聲明子項目中需要用到的依賴jar包,之後,當某個或者某幾個子項目需要加載該插件的時候,就可以在子項目中dependencies節點隻配置 groupId 和
artifactId就可以完成插件的引用。
dependencyManagement主要是為了統一管理插件,確定所有子項目使用的插件版本保持一緻,類似的還是plugins和pluginManagement。
更多閱讀
maven 線上筆記: https://dunwu.github.io/blog/tags/maven/
參考資料
https://maven.apache.org/index.html——官方文檔位址
http://www.oschina.net/question/158170_29368 http://www.cnblogs.com/crazy-fox/archive/2012/02/09/2343722.html