maven學習2——pom.xml
阿新 • • 發佈:2019-01-10
1.前言
Maven,發音是[`meivin],"專家"的意思。它是一個很好的專案管理工具,很早就進入了我的必備工具行列,但是這次為了把project1專案完全遷移並應用maven,所以對maven進行了一些深入的學習。寫這個學習筆記的目的,一個是為了自己備忘,二則希望能夠為其他人學習使用maven 縮短一些時間。
2.命令
mvn pom.xml檔案配置詳解
http://maven.apache.org/ref/2.0.8/maven-model/maven.html
mvn -version/-v 顯示版本資訊
mvn archetype:generate 建立mvn專案
mvn archetype:create -DgroupId=com.oreilly -DartifactId=my-app 建立mvn專案
mvn package 生成target目錄,編譯、測試程式碼,生成測試報告,生成jar/war檔案
mvn jetty:run 執行專案於jetty上,
mvn compile 編譯
mvn test 編譯並測試
mvn clean 清空生成的檔案
mvn site 生成專案相關資訊的網站
mvn -Dwtpversion=1.0 eclipse:eclipse 生成Wtp外掛的Web專案
mvn -Dwtpversion=1.0 eclipse:clean 清除Eclipse專案的配置資訊(Web專案)
mvn eclipse:eclipse 將專案轉化為Eclipse專案
在應用程式用使用多個儲存庫
<repositories>
<repository>
<id>Ibiblio</id>
<name>Ibiblio</name>
<url>http://www.ibiblio.org/maven/</url>
</repository>
<repository>
<id>PlanetMirror</id>
<name>Planet Mirror</name>
<url>http://public.planetmirror.com/pub/maven/</url>
</repository>
</repositories>
mvn deploy:deploy-file -DgroupId=com -DartifactId=client -Dversion=0.1.0 -Dpackaging=jar -Dfile=d:\client-0.1.0.jar -DrepositoryId=maven-repository-inner -Durl=ftp://xxxxxxx/opt/maven/repository/
釋出第三方Jar到本地庫中:
mvn install:install-file -DgroupId=com -DartifactId=client -Dversion=0.1.0 -Dpackaging=jar -Dfile=d:\client-0.1.0.jar
-DdownloadSources=true
-DdownloadJavadocs=true
mvn -e 顯示詳細錯誤 資訊.
mvn validate 驗證工程是否正確,所有需要的資源是否可用。
mvn test-compile 編譯專案測試程式碼。 。
mvn integration-test 在整合測試可以執行的環境中處理和釋出包。
mvn verify 執行任何檢查,驗證包是否有效且達到質量標準。
mvn generate-sources 產生應用需要的任何額外的原始碼,如xdoclet。
2. maven概要
首先我把maven的概念快速的梳理一下,讓我們快速地建立起一個比較精確的maven應用場景。
2.1 maven不是什麼
讀書時候要先限定範圍,避免一些有害的遐想。要說maven不是什麼,我們可以從如下幾個要點來展開
maven不是ant,也不是make。
我們以前接觸的構建工具,需要寫一些詳細的步驟,比如: compile project1/src/*.java 等類似的語句。這些語句正是我們使用ant和make所要編寫的東西。maven採用了"約定優於配置"的方法,一些開發常用的操作和步驟已經固化在 maven中,所以使用者不再需要去編寫那些煩人的語句了。同時,maven內建了開發流程的支援,它不僅能夠編譯,同樣能夠打包、釋出,也能夠一氣呵成做完這些所有的步驟。
maven不是ivy
依賴管理是maven的功能之一,雖然很多人包括我以前都是隻用它的依賴管理功能,但是要深入運用的話,我們就可以看到更多的內容。更重要的是,maven在依賴關係中加入了scope的概念,進一步細化了依賴關係的劃分。
2.2 maven是什麼
maven將自己定位為一個專案管理工具。它負責管理專案開發過程中的幾乎所有的東西:
版本
maven有自己的版本定義和規則
構建
maven支援許多種的應用程式型別,對於每一種支援的應用程式型別都定義好了一組構建規則和工具集。
輸出物管理
maven可以管理專案構建的產物,並將其加入到使用者庫中。這個功能可以用於專案組和其他部門之間的交付行為。
依賴關係
maven對依賴關係的特性進行細緻的分析和劃分,避免開發過程中的依賴混亂和相互汙染行為
文件和構建結果
maven的site命令支援各種文件資訊的釋出,包括構建過程的各種輸出,javadoc,產品文件等。
專案關係
一個大型的專案通常有幾個小專案或者模組組成,用maven可以很方便地管理
移植性管理
maven可以針對不同的開發場景,輸出不同種類的輸出結果。
2.3 maven的生命週期
maven把專案的構建劃分為不同的生命週期(lifecycle),在我看來,劃分的已經是非常仔細了,大家可以參考這裡。粗略一點的話,它這個過程(phase)包括:編譯、測試、打包、整合測試、驗證、部署。maven中所有的執行動作(goal)都需要指明自己在這個過程中的執行位置,然後maven執行的時候,就依照過程的發展依次呼叫這些goal進行各種處理。
這個也是maven的一個基本排程機制。一般來說,位置稍後的過程都會依賴於之前的過程。當然,maven同樣提供了配置檔案,可以依照使用者要求,跳過某些階段。
2.4 maven的"約定優於配置"
所謂的"約定優於配置",在maven中並不是完全不可以修改的,他們只是一些配置的預設值而已。但是使用者除非必要,並不需要去修改那些約定內容。maven預設的檔案存放結構如下:
/專案目錄
pom.xml 用於maven的配置檔案
/src 原始碼目錄
/src/main 工程原始碼目錄
/src/main/java 工程java原始碼目錄
/src/main/resource 工程的資源目錄
/src/test 單元測試目錄
/src/test/java
/target 輸出目錄,所有的輸出物都存放在這個目錄下
/target/classes 編譯之後的class檔案
每一個階段的任務都知道怎麼正確完成自己的工作,比如compile任務就知道從src/main/java下編譯所有的java檔案,並把它的輸出class檔案存放到target/classes中。
對maven來說,採用"約定優於配置"的策略可以減少修改配置的工作量,也可以降低學習成本,更重要的是,給專案引入了統一的規範。
2.5 maven的版本規範
maven使用如下幾個要素來唯一定位某一個輸出物: groupId:artifactId:packaging:version 。比如org.springframework:spring:2.5 。每個部分的解釋如下:
groupId
團體,公司,小組,組織,專案,或者其它團體。團體標識的約定是,它以建立這個專案的組織名稱的逆向域名(reverse domain name)開頭。來自Sonatype的專案有一個以com.sonatype開頭的groupId,而Apache Software的專案有以org.apache開頭的groupId。
artifactId
在groupId下的表示一個單獨專案的唯一識別符號。比如我們的tomcat, commons等。不要在artifactId中包含點號(.)。
version
一個專案的特定版本。釋出的專案有一個固定的版本標識來指向該專案的某一個特定的版本。而正在開發中的專案可以用一個特殊的標識,這種標識給版本加上一個"SNAPSHOT"的標記。
雖然專案的打包格式也是Maven座標的重要組成部分,但是它不是專案唯一識別符號的一個部分。一個專案的 groupId:artifactId:version使之成為一個獨一無二的專案;你不能同時有一個擁有同樣的groupId, artifactId和version標識的專案。
packaging
專案的型別,預設是jar,描述了專案打包後的輸出。型別為jar的專案產生一個JAR檔案,型別為war的專案產生一個web應用。
classifier
很少使用的座標,一般都可以忽略classifiers。如果你要釋出同樣的程式碼,但是由於技術原因需要生成兩個單獨的構件,你就要使用一個分類器(classifier)。例如,如果你想要構建兩個單獨的構件成JAR,一個使用Java 1.4編譯器,另一個使用Java 6編譯器,你就可以使用分類器來生成兩個單獨的JAR構件,它們有同樣的groupId:artifactId:version組合。如果你的專案使用本地擴充套件類庫,你可以使用分類器為每一個目標平臺生成一個構件。分類器常用於打包構件的原始碼,JavaDoc或者二進位制集合。
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
如果一個版本包含字串"SNAPSHOT",Maven就會在安裝或釋出這個元件的時候將該符號展開為一個日期和時間值,轉換為UTC時間。例如,"1.0-SNAPSHOT"會在2010年5月5日下午2點10分發布時候變成1.0-20100505-141000-1。
這個詞只能用於開發過程中,因為一般來說,專案組都會頻繁釋出一些版本,最後實際釋出的時候,會在這些snapshot版本中尋找一個穩定的,用於正式釋出,比如1.4版本釋出之前,就會有一系列的1.4-SNAPSHOT,而實際釋出的1.4,也是從中拿出來的一個穩定版。
LATEST
指某個特定構件的最新發布,這個釋出可能是一個釋出版,也可能是一個snapshot版,具體看哪個時間最後。
RELEASE
指最後一個釋出版。
2.6 maven的組成部分
maven把整個maven管理的專案分為幾個部分,一個部分是原始碼,包括原始碼本身、相關的各種資源,一個部分則是單元測試用例,另外一部分則是各種maven的外掛。對於這幾個部分,maven可以獨立管理他們,包括各種外部依賴關係。
2.7 maven的依賴管理
依賴管理一般是最吸引人使用maven的功能特性了,這個特性讓開發者只需要關注程式碼的直接依賴,比如我們用了spring,就加入spring依賴說明就可以了,至於spring自己還依賴哪些外部的東西,maven幫我們搞定。
任意一個外部依賴說明包含如下幾個要素:groupId, artifactId, version, scope, type, optional。其中前3個是必須的,各自含義如下:
groupId 必須
artifactId 必須
version 必須。
這裡的version可以用區間表示式來表示,比如(2.0,)表示>2.0,[2.0,3.0)表示2.0<=ver<3.0;多個條件之間用逗號分隔,比如[1,3),[5,7]。
scope 作用域限制
type 一般在pom引用依賴時候出現,其他時候不用
optional 是否可選依賴
maven認為,程式對外部的依賴會隨著程式的所處階段和應用場景而變化,所以maven中的依賴關係有作用域(scope)的限制。在maven中,scope包含如下的取值:
compile(編譯範圍)
compile是預設的範圍;如果沒有提供一個範圍,那該依賴的範圍就是編譯範圍。編譯範圍依賴在所有的classpath中可用,同時它們也會被打包。
provided(已提供範圍)
provided依賴只有在當JDK或者一個容器已提供該依賴之後才使用。例如,如果你開發了一個web應用,你可能在編譯classpath中需要可用的Servlet API來編譯一個servlet,但是你不會想要在打包好的WAR中包含這個Servlet API;這個Servlet API JAR由你的應用伺服器或者servlet容器提供。已提供範圍的依賴在編譯classpath(不是執行時)可用。它們不是傳遞性的,也不會被打包。
runtime(執行時範圍)
runtime依賴在執行和測試系統的時候需要,但在編譯的時候不需要。比如,你可能在編譯的時候只需要JDBC API JAR,而只有在執行的時候才需要JDBC驅動實現。
test(測試範圍)
test範圍依賴 在一般的 編譯和執行時都不需要,它們只有在測試編譯和測試執行階段可用。測試範圍依賴在之前的???中介紹過。
system(系統範圍)
system範圍依賴與provided類似,但是你必須顯式的提供一個對於本地系統中JAR檔案的路徑。這麼做是為了允許基於本地物件編譯,而這些物件是系統類庫的一部分。這樣的構件應該是一直可用的,Maven也不會在倉庫中去尋找它。 如果你將一個依賴範圍設定成系統範圍,你必須同時提供一個systemPath元素 。注意該範圍是不推薦使用的(你應該一直儘量去從公共或定製的Maven倉庫中引用依賴)。
另外,程式碼有程式碼自己的依賴,各個maven使用的外掛也可以有自己的依賴關係。依賴也可以是可選的,比如我們程式碼中沒有任何cache依賴,但是hibernate可能要配置cache,所以該cache的依賴就是可選的。
2.8 多專案管理
maven的多專案管理也是非常強大的。一般來說,maven要求同一個工程的所有子專案都放置到同一個目錄下,每一個子目錄代表一個專案,比如
總專案/
pom.xml 總專案的pom配置檔案
子專案1/
pom.xml 子專案1的pom檔案
子專案2/
pom.xml 子專案2的pom檔案
按照這種格式存放,就是繼承方式,所有具體子專案的pom.xml都會繼承總專案pom的內容,取值為子專案pom內容優先。
要設定繼承方式,首先要在總專案的pom中加入如下配置
<modules>
<module>simple-weather</module>
<module>simple-webapp</module>
</modules>
其次在每個子專案中加入
<parent>
<groupId>org.sonatype.mavenbook.ch06</groupId>
<artifactId>simple-parent</artifactId>
<version>1.0</version>
</parent>
即可。
當然,繼承不是唯一的配置檔案共用方式,maven還支援引用方式。引用pom的方式更簡單,在依賴中加入一個type為pom的依賴即可。
<project>
<description>This is a project requiring JDBC</description>
...
<dependencies>
...
<dependency>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
2.9 屬性
使用者可以在maven中定義一些屬性,然後在其他地方用${xxx}進行引用。比如:
<project>
<modelVersion>4.0.0</modelVersion>
...
<properties>
<var1>value1</var1>
</properties>
</project>
maven提供了三個隱式的變數,用來訪問系統環境變數、POM資訊和maven的settings:
env
暴露作業系統的環境變數,比如env.PATH
project
暴露POM中的內容,用點號(.)的路徑來引用POM元素的值,比如${project.artifactId}。另外,java的系統屬性比如user.dir等,也暴露在這裡。
settings
暴露maven的settings的資訊,也可以用點號(.)來引用。maven把系統配置檔案存放在maven的安裝目錄中,把使用者相關的配置檔案存放在~/.m2/settings.xml(unix)或者%USERPROFILE%/.m2/settings.xml(windows)中。
2.10 maven的profile
profile是maven的一個重要特性,它可以讓maven能夠自動適應外部的環境變化,比如同一個專案,在linux下編譯linux的版本,在win下編譯win的版本等。一個專案可以設定多個profile,也可以在同一時間設定多個profile被啟用(active)的。自動啟用的 profile的條件可以是各種各樣的設定條件,組合放置在activation節點中,也可以通過命令列直接指定。profile包含的其他配置內容可以覆蓋掉pom定義的相應值。如果認為profile設定比較複雜,可以將所有的profiles內容移動到專門的 profiles.xml 檔案中,不過記得和pom.xml放在一起。
activation節點中的啟用條件中常見的有如下幾個:
os
判斷作業系統相關的引數,它包含如下可以自由組合的子節點元素
message - 規則失敗之後顯示的訊息
arch - 匹配cpu結構,常見為x86
family - 匹配作業系統家族,常見的取值為:dos,mac,netware,os/2,unix,windows,win9x,os/400等
name - 匹配作業系統的名字
version - 匹配的作業系統版本號
display - 檢測到作業系統之後顯示的資訊
jdk
檢查jdk版本,可以用區間表示。
property
檢查屬性值,本節點可以包含name和value兩個子節點。
file
檢查檔案相關內容,包含兩個子節點:exists和missing,用於分別檢查檔案存在和不存在兩種情況。
3. maven的操作和使用
maven的操作有兩種方式,一種是通過mvn命令列命令,一種是使用maven的eclipse外掛。因為使用eclipse的maven外掛操作起來比較容易,這裡就只介紹使用mvn命令列的操作。
3.1 maven的配置檔案
maven的主執行程式為mvn.bat,linux下為mvn.sh,這兩個程式都很簡單,它們的共同用途就是收集一些引數,然後用 java.exe來執行maven的Main函式。maven同樣需要有配置檔案,名字叫做settings.xml,它放在兩個地方,一個是maven 安裝目錄的conf目錄下,對所有使用該maven的使用者都起作用,我們稱為主配置檔案,另外一個放在 %USERPROFILE%/.m2/settings.xml下,我們成為使用者配置檔案,只對當前使用者有效,且可以覆蓋主配置檔案的引數內容。還有就是專案級別的配置資訊了,它存放在每一個maven管理的專案目錄下,叫pom.xml,主要用於配置專案相關的一些內容,當然,如果有必要,使用者也可以在 pom中寫一些配置,覆蓋住配置檔案和使用者配置檔案的設定引數內容。
一般來說,settings檔案配置的是比如repository庫路徑之類的全域性資訊,具體可以參考官方網站的文章 。
3.2 建立新工程
要建立一個新的maven工程,我們需要給我們的工程指定幾個必要的要素,就是maven產品座標的幾個要素:groupId, artifactId,如果願意,你也可以指定version和package名稱。我們先看一個簡單的建立命令:
d:\work\temp>mvn archetype:create -DgroupId=com.abc -DartifactId=product1 -DarchetypeArtifactId=maven-archetype-webapp
首先看這裡的命令列引數的傳遞結構,怪異的 -D引數=值 的方式是 java.exe 要求的方式。這個命令建立一個web工程,目錄結構是一個標準的maven結構,如下:
D:.
└─mywebapp
│ pom.xml
│
└─src
└─main
├─resources
└─webapp
│ index.jsp
│
└─WEB-INF
web.xml
大家要注意,這裡目錄結構的佈局實際上是由引數 archetypeArtifactId 來決定的,因為這裡傳入的是 maven-archetype-webapp 如果我們傳入其他的就會建立不同的結構,預設值為 maven-archetype-quickstart ,有興趣的讀者可以參考更詳細的列表 ,我把部分常用的列表在這裡:
Artifact Group Version Repository Description
maven-archetype-j2ee-simple org.apache.maven.archetypes A simple J2EE Java application
maven-archetype-marmalade-mojo org.apache.maven.archetypes A Maven plugin development project using marmalade
maven-archetype-plugin org.apache.maven.archetypes A Maven Java plugin development project
maven-archetype-portlet org.apache.maven.archetypes A simple portlet application
maven-archetype-profiles org.apache.maven.archetypes
maven-archetype-quickstart org.apache.maven.archetypes
maven-archetype-simple org.apache.maven.archetypes
maven-archetype-site-simple org.apache.maven.archetypes A simple site generation project
maven-archetype-site org.apache.maven.archetypes A more complex site project
maven-archetype-webapp org.apache.maven.archetypes A simple Java web application
maven-archetype-har net.sf.maven-har 0.9 Hibernate Archive
maven-archetype-sar net.sf.maven-sar 0.9 JBoss Service Archive
大家可以參考更詳細的 archetype:create 幫助 和 archtype參考資訊 。
3.3 maven的多專案管理
多專案管理是maven的主要特色之一,對於一個大型工程,用maven來管理他們之間複雜的依賴關係,是再好不過了。maven的專案配置之間的關係有兩種:繼承關係和引用關係。
maven預設根據目錄結構來設定pom的繼承關係,即下級目錄的pom預設繼承上級目錄的pom。要設定兩者之間的關係很簡單,上級pom如下設定:
<modules>
<module>ABCCommon</module>
<module>ABCCore</module>
<module>ABCTools</module>
</modules>
要記住的是,這裡的module是目錄名,不是子工程的artifactId。子工程如下設定:
<parent>
<groupId>com.abc.product1</groupId>
<artifactId>abc-product1</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>abc-my-module2</artifactId>
<packaging>jar</packaging>
這樣兩者就相互關聯起來了,繼承關係就設定完畢,所有父工程的配置內容都會自動在子工程中生效,除非子工程有相同的配置覆蓋。如果你不喜歡層層遞進的目錄結構來實現繼承,也可以在parent中加入<relativePath>../a-parent/pom.xml</relativePath> 來制定parent專案的相對目錄。繼承關係通常用在專案共同特性的抽取上,通過抽取公共特性,可以大幅度減少子專案的配置工作量。
引用關係是另外一種複用的方式,maven中配置引用關係也很簡單,加入一個 type 為 pom 的依賴即可。
<dependency>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
但是無論是父專案還是引用專案,這些工程都必須用 mvn install 或者 mvn deploy 安裝到本地庫才行,否則會報告依賴沒有找到,eclipse編譯時候也會出錯。
需要特別提出的是複用過程中,父專案的pom中可以定義 dependencyManagement 節點,其中存放依賴關係,但是這個依賴關係只是定義,不會真的產生效果,如果子專案想要使用這個依賴關係,可以在本身的 dependency 中新增一個簡化的引用
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</dependency>
這種方法可以避免版本號滿天飛的情況。
3.4 安裝庫檔案到maven庫中
在maven中一般都會用到安裝庫檔案的功能,一則是我們常用的hibernate要使用jmx庫,但是因為sun的license限制,所以無法將其直接包含在repository中。所以我們使用mvn命令把jar安裝到我們本地的repository中
mvn install:install-file -DgroupId=com.sun.jdmk -DartifactId=jmxtools -Dversion=1.2.1 -Dpackaging=jar -Dfile=/path/to/file
如果我們想把它安裝到公司的repository中,需要使用命令
mvn deploy:deploy-file -DgroupId=com.sun.jdmk -DartifactId=jmxtools -Dversion=1.2.1 -Dpackaging=jar -Dfile=/path/to/file -Durl=http://xxx.ss.com/sss.xxx -DrepositoryId=release-repo
對於我們的工程輸出,如果需要放置到公司的repository中的話,可以通過配置pom來實現
<distributionManagement>
<repository>
<id>mycompany-repository</id>
<name>MyCompany Repository</name>
<url>scp://repository.mycompany.com/repository/maven2</url>
</repository>
</distributionManagement>
這裡使用的scp方式提交庫檔案,還有其他方式可以使用,請參考faq部分。然後記得在你的settings.xml中加入這一內容
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<servers>
<server>
<id>mycompany-repository</id>
<username>jvanzyl</username>
<!-- Default value is ~/.ssh/id_dsa -->
<privateKey>/path/to/identity</privateKey>
<passphrase>my_key_passphrase</passphrase>
</server>
</servers>
...
</settings>
3.5 maven的變數
maven定義了很多變數屬性,參考這裡 http://docs.codehaus.org/display/MAVENUSER/MavenPropertiesGuide
內建屬性
${basedir } represents the directory containing pom.xml
${version } equivalent to ${project.version } or ${pom.version }
Pom/Project properties
所有pom中的元素都可以用 project. 字首進行引用,以下是部分常用的
${project.build.directory } results in the path to your "target" dir, this is the same as ${pom.project.build.directory }
${project.build. outputD irectory } results in the path to your "target/classes" dir
${project.name } refers to the name of the project.
${project.version } refers to the version of the project.
${project.build.finalName } refers to the final name of the file created when the built project is packaged
本地使用者設定
所有用的的 settings.xml 中的設定都可以通過 settings. 字首進行引用
${settings.localRepository } refers to the path of the user's local repository.
${maven.repo.local } also works for backward compatibility with maven1 ??
環境變數
系統的環境變數通過 env. 字首引用
${env.M2_HOME } returns the Maven2 installation path.
${java.home } specifies the path to the current JRE_HOME environment use with relative paths to get for example:
<jvm>${java.home}../bin/java.exe</jvm>
java系統屬性
所有JVM中定義的java系統屬性.
使用者在pom中定義的自定義屬性
<project>
...
&nbs
Maven,發音是[`meivin],"專家"的意思。它是一個很好的專案管理工具,很早就進入了我的必備工具行列,但是這次為了把project1專案完全遷移並應用maven,所以對maven進行了一些深入的學習。寫這個學習筆記的目的,一個是為了自己備忘,二則希望能夠為其他人學習使用maven 縮短一些時間。
2.命令
mvn pom.xml檔案配置詳解
http://maven.apache.org/ref/2.0.8/maven-model/maven.html
mvn -version/-v 顯示版本資訊
mvn archetype:generate 建立mvn專案
mvn archetype:create -DgroupId=com.oreilly -DartifactId=my-app 建立mvn專案
mvn package 生成target目錄,編譯、測試程式碼,生成測試報告,生成jar/war檔案
mvn jetty:run 執行專案於jetty上,
mvn compile 編譯
mvn test 編譯並測試
mvn clean 清空生成的檔案
mvn site 生成專案相關資訊的網站
mvn -Dwtpversion=1.0 eclipse:eclipse 生成Wtp外掛的Web專案
mvn -Dwtpversion=1.0 eclipse:clean 清除Eclipse專案的配置資訊(Web專案)
mvn eclipse:eclipse 將專案轉化為Eclipse專案
在應用程式用使用多個儲存庫
<repositories>
<repository>
<id>Ibiblio</id>
<name>Ibiblio</name>
<url>http://www.ibiblio.org/maven/</url>
</repository>
<repository>
<id>PlanetMirror</id>
<name>Planet Mirror</name>
<url>http://public.planetmirror.com/pub/maven/</url>
</repository>
</repositories>
mvn deploy:deploy-file -DgroupId=com -DartifactId=client -Dversion=0.1.0 -Dpackaging=jar -Dfile=d:\client-0.1.0.jar -DrepositoryId=maven-repository-inner -Durl=ftp://xxxxxxx/opt/maven/repository/
釋出第三方Jar到本地庫中:
mvn install:install-file -DgroupId=com -DartifactId=client -Dversion=0.1.0 -Dpackaging=jar -Dfile=d:\client-0.1.0.jar
-DdownloadSources=true
-DdownloadJavadocs=true
mvn -e 顯示詳細錯誤 資訊.
mvn validate 驗證工程是否正確,所有需要的資源是否可用。
mvn test-compile 編譯專案測試程式碼。 。
mvn integration-test 在整合測試可以執行的環境中處理和釋出包。
mvn verify 執行任何檢查,驗證包是否有效且達到質量標準。
mvn generate-sources 產生應用需要的任何額外的原始碼,如xdoclet。
2. maven概要
首先我把maven的概念快速的梳理一下,讓我們快速地建立起一個比較精確的maven應用場景。
2.1 maven不是什麼
讀書時候要先限定範圍,避免一些有害的遐想。要說maven不是什麼,我們可以從如下幾個要點來展開
maven不是ant,也不是make。
我們以前接觸的構建工具,需要寫一些詳細的步驟,比如: compile project1/src/*.java 等類似的語句。這些語句正是我們使用ant和make所要編寫的東西。maven採用了"約定優於配置"的方法,一些開發常用的操作和步驟已經固化在 maven中,所以使用者不再需要去編寫那些煩人的語句了。同時,maven內建了開發流程的支援,它不僅能夠編譯,同樣能夠打包、釋出,也能夠一氣呵成做完這些所有的步驟。
maven不是ivy
依賴管理是maven的功能之一,雖然很多人包括我以前都是隻用它的依賴管理功能,但是要深入運用的話,我們就可以看到更多的內容。更重要的是,maven在依賴關係中加入了scope的概念,進一步細化了依賴關係的劃分。
2.2 maven是什麼
maven將自己定位為一個專案管理工具。它負責管理專案開發過程中的幾乎所有的東西:
版本
maven有自己的版本定義和規則
構建
maven支援許多種的應用程式型別,對於每一種支援的應用程式型別都定義好了一組構建規則和工具集。
輸出物管理
maven可以管理專案構建的產物,並將其加入到使用者庫中。這個功能可以用於專案組和其他部門之間的交付行為。
依賴關係
maven對依賴關係的特性進行細緻的分析和劃分,避免開發過程中的依賴混亂和相互汙染行為
文件和構建結果
maven的site命令支援各種文件資訊的釋出,包括構建過程的各種輸出,javadoc,產品文件等。
專案關係
一個大型的專案通常有幾個小專案或者模組組成,用maven可以很方便地管理
移植性管理
maven可以針對不同的開發場景,輸出不同種類的輸出結果。
2.3 maven的生命週期
maven把專案的構建劃分為不同的生命週期(lifecycle),在我看來,劃分的已經是非常仔細了,大家可以參考這裡。粗略一點的話,它這個過程(phase)包括:編譯、測試、打包、整合測試、驗證、部署。maven中所有的執行動作(goal)都需要指明自己在這個過程中的執行位置,然後maven執行的時候,就依照過程的發展依次呼叫這些goal進行各種處理。
這個也是maven的一個基本排程機制。一般來說,位置稍後的過程都會依賴於之前的過程。當然,maven同樣提供了配置檔案,可以依照使用者要求,跳過某些階段。
2.4 maven的"約定優於配置"
所謂的"約定優於配置",在maven中並不是完全不可以修改的,他們只是一些配置的預設值而已。但是使用者除非必要,並不需要去修改那些約定內容。maven預設的檔案存放結構如下:
/專案目錄
pom.xml 用於maven的配置檔案
/src 原始碼目錄
/src/main 工程原始碼目錄
/src/main/java 工程java原始碼目錄
/src/main/resource 工程的資源目錄
/src/test 單元測試目錄
/src/test/java
/target 輸出目錄,所有的輸出物都存放在這個目錄下
/target/classes 編譯之後的class檔案
每一個階段的任務都知道怎麼正確完成自己的工作,比如compile任務就知道從src/main/java下編譯所有的java檔案,並把它的輸出class檔案存放到target/classes中。
對maven來說,採用"約定優於配置"的策略可以減少修改配置的工作量,也可以降低學習成本,更重要的是,給專案引入了統一的規範。
2.5 maven的版本規範
maven使用如下幾個要素來唯一定位某一個輸出物: groupId:artifactId:packaging:version 。比如org.springframework:spring:2.5 。每個部分的解釋如下:
groupId
團體,公司,小組,組織,專案,或者其它團體。團體標識的約定是,它以建立這個專案的組織名稱的逆向域名(reverse domain name)開頭。來自Sonatype的專案有一個以com.sonatype開頭的groupId,而Apache Software的專案有以org.apache開頭的groupId。
artifactId
在groupId下的表示一個單獨專案的唯一識別符號。比如我們的tomcat, commons等。不要在artifactId中包含點號(.)。
version
一個專案的特定版本。釋出的專案有一個固定的版本標識來指向該專案的某一個特定的版本。而正在開發中的專案可以用一個特殊的標識,這種標識給版本加上一個"SNAPSHOT"的標記。
雖然專案的打包格式也是Maven座標的重要組成部分,但是它不是專案唯一識別符號的一個部分。一個專案的 groupId:artifactId:version使之成為一個獨一無二的專案;你不能同時有一個擁有同樣的groupId, artifactId和version標識的專案。
packaging
專案的型別,預設是jar,描述了專案打包後的輸出。型別為jar的專案產生一個JAR檔案,型別為war的專案產生一個web應用。
classifier
很少使用的座標,一般都可以忽略classifiers。如果你要釋出同樣的程式碼,但是由於技術原因需要生成兩個單獨的構件,你就要使用一個分類器(classifier)。例如,如果你想要構建兩個單獨的構件成JAR,一個使用Java 1.4編譯器,另一個使用Java 6編譯器,你就可以使用分類器來生成兩個單獨的JAR構件,它們有同樣的groupId:artifactId:version組合。如果你的專案使用本地擴充套件類庫,你可以使用分類器為每一個目標平臺生成一個構件。分類器常用於打包構件的原始碼,JavaDoc或者二進位制集合。
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
如果一個版本包含字串"SNAPSHOT",Maven就會在安裝或釋出這個元件的時候將該符號展開為一個日期和時間值,轉換為UTC時間。例如,"1.0-SNAPSHOT"會在2010年5月5日下午2點10分發布時候變成1.0-20100505-141000-1。
這個詞只能用於開發過程中,因為一般來說,專案組都會頻繁釋出一些版本,最後實際釋出的時候,會在這些snapshot版本中尋找一個穩定的,用於正式釋出,比如1.4版本釋出之前,就會有一系列的1.4-SNAPSHOT,而實際釋出的1.4,也是從中拿出來的一個穩定版。
LATEST
指某個特定構件的最新發布,這個釋出可能是一個釋出版,也可能是一個snapshot版,具體看哪個時間最後。
RELEASE
指最後一個釋出版。
2.6 maven的組成部分
maven把整個maven管理的專案分為幾個部分,一個部分是原始碼,包括原始碼本身、相關的各種資源,一個部分則是單元測試用例,另外一部分則是各種maven的外掛。對於這幾個部分,maven可以獨立管理他們,包括各種外部依賴關係。
2.7 maven的依賴管理
依賴管理一般是最吸引人使用maven的功能特性了,這個特性讓開發者只需要關注程式碼的直接依賴,比如我們用了spring,就加入spring依賴說明就可以了,至於spring自己還依賴哪些外部的東西,maven幫我們搞定。
任意一個外部依賴說明包含如下幾個要素:groupId, artifactId, version, scope, type, optional。其中前3個是必須的,各自含義如下:
groupId 必須
artifactId 必須
version 必須。
這裡的version可以用區間表示式來表示,比如(2.0,)表示>2.0,[2.0,3.0)表示2.0<=ver<3.0;多個條件之間用逗號分隔,比如[1,3),[5,7]。
scope 作用域限制
type 一般在pom引用依賴時候出現,其他時候不用
optional 是否可選依賴
maven認為,程式對外部的依賴會隨著程式的所處階段和應用場景而變化,所以maven中的依賴關係有作用域(scope)的限制。在maven中,scope包含如下的取值:
compile(編譯範圍)
compile是預設的範圍;如果沒有提供一個範圍,那該依賴的範圍就是編譯範圍。編譯範圍依賴在所有的classpath中可用,同時它們也會被打包。
provided(已提供範圍)
provided依賴只有在當JDK或者一個容器已提供該依賴之後才使用。例如,如果你開發了一個web應用,你可能在編譯classpath中需要可用的Servlet API來編譯一個servlet,但是你不會想要在打包好的WAR中包含這個Servlet API;這個Servlet API JAR由你的應用伺服器或者servlet容器提供。已提供範圍的依賴在編譯classpath(不是執行時)可用。它們不是傳遞性的,也不會被打包。
runtime(執行時範圍)
runtime依賴在執行和測試系統的時候需要,但在編譯的時候不需要。比如,你可能在編譯的時候只需要JDBC API JAR,而只有在執行的時候才需要JDBC驅動實現。
test(測試範圍)
test範圍依賴 在一般的 編譯和執行時都不需要,它們只有在測試編譯和測試執行階段可用。測試範圍依賴在之前的???中介紹過。
system(系統範圍)
system範圍依賴與provided類似,但是你必須顯式的提供一個對於本地系統中JAR檔案的路徑。這麼做是為了允許基於本地物件編譯,而這些物件是系統類庫的一部分。這樣的構件應該是一直可用的,Maven也不會在倉庫中去尋找它。 如果你將一個依賴範圍設定成系統範圍,你必須同時提供一個systemPath元素 。注意該範圍是不推薦使用的(你應該一直儘量去從公共或定製的Maven倉庫中引用依賴)。
另外,程式碼有程式碼自己的依賴,各個maven使用的外掛也可以有自己的依賴關係。依賴也可以是可選的,比如我們程式碼中沒有任何cache依賴,但是hibernate可能要配置cache,所以該cache的依賴就是可選的。
2.8 多專案管理
maven的多專案管理也是非常強大的。一般來說,maven要求同一個工程的所有子專案都放置到同一個目錄下,每一個子目錄代表一個專案,比如
總專案/
pom.xml 總專案的pom配置檔案
子專案1/
pom.xml 子專案1的pom檔案
子專案2/
pom.xml 子專案2的pom檔案
按照這種格式存放,就是繼承方式,所有具體子專案的pom.xml都會繼承總專案pom的內容,取值為子專案pom內容優先。
要設定繼承方式,首先要在總專案的pom中加入如下配置
<modules>
<module>simple-weather</module>
<module>simple-webapp</module>
</modules>
其次在每個子專案中加入
<parent>
<groupId>org.sonatype.mavenbook.ch06</groupId>
<artifactId>simple-parent</artifactId>
<version>1.0</version>
</parent>
即可。
當然,繼承不是唯一的配置檔案共用方式,maven還支援引用方式。引用pom的方式更簡單,在依賴中加入一個type為pom的依賴即可。
<project>
<description>This is a project requiring JDBC</description>
...
<dependencies>
...
<dependency>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
</dependencies>
</project>
2.9 屬性
使用者可以在maven中定義一些屬性,然後在其他地方用${xxx}進行引用。比如:
<project>
<modelVersion>4.0.0</modelVersion>
...
<properties>
<var1>value1</var1>
</properties>
</project>
maven提供了三個隱式的變數,用來訪問系統環境變數、POM資訊和maven的settings:
env
暴露作業系統的環境變數,比如env.PATH
project
暴露POM中的內容,用點號(.)的路徑來引用POM元素的值,比如${project.artifactId}。另外,java的系統屬性比如user.dir等,也暴露在這裡。
settings
暴露maven的settings的資訊,也可以用點號(.)來引用。maven把系統配置檔案存放在maven的安裝目錄中,把使用者相關的配置檔案存放在~/.m2/settings.xml(unix)或者%USERPROFILE%/.m2/settings.xml(windows)中。
2.10 maven的profile
profile是maven的一個重要特性,它可以讓maven能夠自動適應外部的環境變化,比如同一個專案,在linux下編譯linux的版本,在win下編譯win的版本等。一個專案可以設定多個profile,也可以在同一時間設定多個profile被啟用(active)的。自動啟用的 profile的條件可以是各種各樣的設定條件,組合放置在activation節點中,也可以通過命令列直接指定。profile包含的其他配置內容可以覆蓋掉pom定義的相應值。如果認為profile設定比較複雜,可以將所有的profiles內容移動到專門的 profiles.xml 檔案中,不過記得和pom.xml放在一起。
activation節點中的啟用條件中常見的有如下幾個:
os
判斷作業系統相關的引數,它包含如下可以自由組合的子節點元素
message - 規則失敗之後顯示的訊息
arch - 匹配cpu結構,常見為x86
family - 匹配作業系統家族,常見的取值為:dos,mac,netware,os/2,unix,windows,win9x,os/400等
name - 匹配作業系統的名字
version - 匹配的作業系統版本號
display - 檢測到作業系統之後顯示的資訊
jdk
檢查jdk版本,可以用區間表示。
property
檢查屬性值,本節點可以包含name和value兩個子節點。
file
檢查檔案相關內容,包含兩個子節點:exists和missing,用於分別檢查檔案存在和不存在兩種情況。
3. maven的操作和使用
maven的操作有兩種方式,一種是通過mvn命令列命令,一種是使用maven的eclipse外掛。因為使用eclipse的maven外掛操作起來比較容易,這裡就只介紹使用mvn命令列的操作。
3.1 maven的配置檔案
maven的主執行程式為mvn.bat,linux下為mvn.sh,這兩個程式都很簡單,它們的共同用途就是收集一些引數,然後用 java.exe來執行maven的Main函式。maven同樣需要有配置檔案,名字叫做settings.xml,它放在兩個地方,一個是maven 安裝目錄的conf目錄下,對所有使用該maven的使用者都起作用,我們稱為主配置檔案,另外一個放在 %USERPROFILE%/.m2/settings.xml下,我們成為使用者配置檔案,只對當前使用者有效,且可以覆蓋主配置檔案的引數內容。還有就是專案級別的配置資訊了,它存放在每一個maven管理的專案目錄下,叫pom.xml,主要用於配置專案相關的一些內容,當然,如果有必要,使用者也可以在 pom中寫一些配置,覆蓋住配置檔案和使用者配置檔案的設定引數內容。
一般來說,settings檔案配置的是比如repository庫路徑之類的全域性資訊,具體可以參考官方網站的文章 。
3.2 建立新工程
要建立一個新的maven工程,我們需要給我們的工程指定幾個必要的要素,就是maven產品座標的幾個要素:groupId, artifactId,如果願意,你也可以指定version和package名稱。我們先看一個簡單的建立命令:
d:\work\temp>mvn archetype:create -DgroupId=com.abc -DartifactId=product1 -DarchetypeArtifactId=maven-archetype-webapp
首先看這裡的命令列引數的傳遞結構,怪異的 -D引數=值 的方式是 java.exe 要求的方式。這個命令建立一個web工程,目錄結構是一個標準的maven結構,如下:
D:.
└─mywebapp
│ pom.xml
│
└─src
└─main
├─resources
└─webapp
│ index.jsp
│
└─WEB-INF
web.xml
大家要注意,這裡目錄結構的佈局實際上是由引數 archetypeArtifactId 來決定的,因為這裡傳入的是 maven-archetype-webapp 如果我們傳入其他的就會建立不同的結構,預設值為 maven-archetype-quickstart ,有興趣的讀者可以參考更詳細的列表 ,我把部分常用的列表在這裡:
Artifact Group Version Repository Description
maven-archetype-j2ee-simple org.apache.maven.archetypes A simple J2EE Java application
maven-archetype-marmalade-mojo org.apache.maven.archetypes A Maven plugin development project using marmalade
maven-archetype-plugin org.apache.maven.archetypes A Maven Java plugin development project
maven-archetype-portlet org.apache.maven.archetypes A simple portlet application
maven-archetype-profiles org.apache.maven.archetypes
maven-archetype-quickstart org.apache.maven.archetypes
maven-archetype-simple org.apache.maven.archetypes
maven-archetype-site-simple org.apache.maven.archetypes A simple site generation project
maven-archetype-site org.apache.maven.archetypes A more complex site project
maven-archetype-webapp org.apache.maven.archetypes A simple Java web application
maven-archetype-har net.sf.maven-har 0.9 Hibernate Archive
maven-archetype-sar net.sf.maven-sar 0.9 JBoss Service Archive
大家可以參考更詳細的 archetype:create 幫助 和 archtype參考資訊 。
3.3 maven的多專案管理
多專案管理是maven的主要特色之一,對於一個大型工程,用maven來管理他們之間複雜的依賴關係,是再好不過了。maven的專案配置之間的關係有兩種:繼承關係和引用關係。
maven預設根據目錄結構來設定pom的繼承關係,即下級目錄的pom預設繼承上級目錄的pom。要設定兩者之間的關係很簡單,上級pom如下設定:
<modules>
<module>ABCCommon</module>
<module>ABCCore</module>
<module>ABCTools</module>
</modules>
要記住的是,這裡的module是目錄名,不是子工程的artifactId。子工程如下設定:
<parent>
<groupId>com.abc.product1</groupId>
<artifactId>abc-product1</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>abc-my-module2</artifactId>
<packaging>jar</packaging>
這樣兩者就相互關聯起來了,繼承關係就設定完畢,所有父工程的配置內容都會自動在子工程中生效,除非子工程有相同的配置覆蓋。如果你不喜歡層層遞進的目錄結構來實現繼承,也可以在parent中加入<relativePath>../a-parent/pom.xml</relativePath> 來制定parent專案的相對目錄。繼承關係通常用在專案共同特性的抽取上,通過抽取公共特性,可以大幅度減少子專案的配置工作量。
引用關係是另外一種複用的方式,maven中配置引用關係也很簡單,加入一個 type 為 pom 的依賴即可。
<dependency>
<groupId>org.sonatype.mavenbook</groupId>
<artifactId>persistence-deps</artifactId>
<version>1.0</version>
<type>pom</type>
</dependency>
但是無論是父專案還是引用專案,這些工程都必須用 mvn install 或者 mvn deploy 安裝到本地庫才行,否則會報告依賴沒有找到,eclipse編譯時候也會出錯。
需要特別提出的是複用過程中,父專案的pom中可以定義 dependencyManagement 節點,其中存放依賴關係,但是這個依賴關係只是定義,不會真的產生效果,如果子專案想要使用這個依賴關係,可以在本身的 dependency 中新增一個簡化的引用
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</dependency>
這種方法可以避免版本號滿天飛的情況。
3.4 安裝庫檔案到maven庫中
在maven中一般都會用到安裝庫檔案的功能,一則是我們常用的hibernate要使用jmx庫,但是因為sun的license限制,所以無法將其直接包含在repository中。所以我們使用mvn命令把jar安裝到我們本地的repository中
mvn install:install-file -DgroupId=com.sun.jdmk -DartifactId=jmxtools -Dversion=1.2.1 -Dpackaging=jar -Dfile=/path/to/file
如果我們想把它安裝到公司的repository中,需要使用命令
mvn deploy:deploy-file -DgroupId=com.sun.jdmk -DartifactId=jmxtools -Dversion=1.2.1 -Dpackaging=jar -Dfile=/path/to/file -Durl=http://xxx.ss.com/sss.xxx -DrepositoryId=release-repo
對於我們的工程輸出,如果需要放置到公司的repository中的話,可以通過配置pom來實現
<distributionManagement>
<repository>
<id>mycompany-repository</id>
<name>MyCompany Repository</name>
<url>scp://repository.mycompany.com/repository/maven2</url>
</repository>
</distributionManagement>
這裡使用的scp方式提交庫檔案,還有其他方式可以使用,請參考faq部分。然後記得在你的settings.xml中加入這一內容
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<servers>
<server>
<id>mycompany-repository</id>
<username>jvanzyl</username>
<!-- Default value is ~/.ssh/id_dsa -->
<privateKey>/path/to/identity</privateKey>
<passphrase>my_key_passphrase</passphrase>
</server>
</servers>
...
</settings>
3.5 maven的變數
maven定義了很多變數屬性,參考這裡 http://docs.codehaus.org/display/MAVENUSER/MavenPropertiesGuide
內建屬性
${basedir } represents the directory containing pom.xml
${version } equivalent to ${project.version } or ${pom.version }
Pom/Project properties
所有pom中的元素都可以用 project. 字首進行引用,以下是部分常用的
${project.build.directory } results in the path to your "target" dir, this is the same as ${pom.project.build.directory }
${project.build. outputD irectory } results in the path to your "target/classes" dir
${project.name } refers to the name of the project.
${project.version } refers to the version of the project.
${project.build.finalName } refers to the final name of the file created when the built project is packaged
本地使用者設定
所有用的的 settings.xml 中的設定都可以通過 settings. 字首進行引用
${settings.localRepository } refers to the path of the user's local repository.
${maven.repo.local } also works for backward compatibility with maven1 ??
環境變數
系統的環境變數通過 env. 字首引用
${env.M2_HOME } returns the Maven2 installation path.
${java.home } specifies the path to the current JRE_HOME environment use with relative paths to get for example:
<jvm>${java.home}../bin/java.exe</jvm>
java系統屬性
所有JVM中定義的java系統屬性.
使用者在pom中定義的自定義屬性
<project>
...
&nbs