天天看點

maven教程

1.前言

Maven,發音是[`meivin],"專家"的 意思。它是一個很好的項目管理工具,很早就進入了我的必備工具行列,但是這次為了把project1項目完全遷移并應用maven,是以對maven進行 了一些深入的學習。寫這個學習筆記的目的,一個是為了自己備忘,二則希望能夠為其他人學習使用maven 縮短一些時間。

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}進行引用。比如:

    < modelVersion > 4.0.0 </ modelVersion >

    < properties >

        < var1 > value1 </ var1 >

    </ properties >

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如下設定:

    < module > ABCCommon </ module >

    < module > ABCCore </ module >

    < module > ABCTools </ module >

要記住的是,這裡的module是目錄名,不是子工程的artifactId。子工程如下設定:

    < 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 >

    < type > pom </ type >

</ dependency >

但是無論是父項目還是引用項目,這些工程都必須用 mvn install 或者 mvn deploy 安裝到本地庫才行,否則會報告依賴沒有找到,eclipse編譯時候也會出錯。

需要特别提出的是複用過程中,父項目的pom中可以定義 dependencyManagement 節點,其中存放依賴關系,但是這個依賴關系隻是定義,不會真的産生效果,如果子項目想要使用這個依賴關系,可以在本身的 dependency 中添加一個簡化的引用

    < groupId > org.springframework </ groupId >

    < artifactId > spring </ artifactId >

這種方法可以避免版本号滿天飛的情況。

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中定義的自定義屬性

        < my.filter.value > hello </ my.filter.value >

則引用 ${my.filter.value } 就會得到值 hello 

上級工程的變量

上級工程的pom中的變量用字首 ${project.parent } 引用. 上級工程的版本也可以這樣引用: ${parent.version }.

3.6 maven的使用

我們已經知道maven預定義了許多的階段(phase),每個插件都依附于這些階段,并且在進入某個階段的時候,調用運作這些相關插件的功能。我們先來看完整的maven生命周期:

生命周期 階段描述

validate 驗證項目是否正确,以及所有為了完整建構必要的資訊是否可用

generate-sources 生成所有需要包含在編譯過程中的源代碼

process-sources 處理源代碼,比如過濾一些值

generate-resources 生成所有需要包含在打包過程中的資源檔案

process-resources 複制并處理資源檔案至目标目錄,準備打包

compile 編譯項目的源代碼

process-classes 後處理編譯生成的檔案,例如對Java類進行位元組碼增強(bytecode enhancement)

generate-test-sources 生成所有包含在測試編譯過程中的測試源碼

process-test-sources 處理測試源碼,比如過濾一些值

generate-test-resources 生成測試需要的資源檔案

process-test-resources 複制并處理測試資源檔案至測試目标目錄

test-compile 編譯測試源碼至測試目标目錄

test 使用合适的單元測試架構運作測試。這些測試應該不需要代碼被打包或釋出

prepare-package 在真正的打包之前,執行一些準備打包必要的操作。這通常會産生一個包的展開的處理過的版本(将會在Maven 2.1+中實作)

package 将編譯好的代碼打包成可分發的格式,如JAR,WAR,或者EAR

pre-integration-test 執行一些在內建測試運作之前需要的動作。如建立內建測試需要的環境

integration-test 如果有必要的話,處理包并釋出至內建測試可以運作的環境

post-integration-test 執行一些在內建測試運作之後需要的動作。如清理內建測試環境。

verify 執行所有檢查,驗證包是有效的,符合品質規範

install 安裝包至本地倉庫,以備本地的其它項目作為依賴使用

deploy 複制最終的包至遠端倉庫,共享給其它開發人員和項目(通常和一次正式的釋出相關)

maven核心的插件清單可以參考 http://maven.apache.org/plugins/index.html 。這裡僅列舉幾個常用的插件及其配置參數:

clean插件

隻包含一個goal叫做 clean:clean ,負責清理建構時候建立的檔案。 預設清理的位置是如下幾個變量指定的路徑 project.build.directory, project.build.outputDirectory, project.build.testOutputDirectory, and project.reporting.outputDirectory 。

compiler插件

包含2個goal,分别是 compiler:compile 和 compiler:testCompile 。可以到這裡檢視兩者的具體參數設定:compile , testCompile 。

surefire插件

運作單元測試用例的插件,并且能夠生成報表。包含一個goal為 surefire:test 。主要參數testSourceDirectory用來指定測試用例目錄,參考完整用法幫助

jar

負責将工程輸出打包到jar檔案中。包含兩個goal,分别是 jar:jar , jar:test-jar 。兩個goal負責從classesDirectory或testClassesDirectory中擷取所有資源,然後輸出jar檔案到outputDirectory中。

war

負責打包成war檔案。常用goal有 war:war ,負責從warSourceDirectory(預設${basedir}/src/main/webapp)打包所有資源到outputDirectory中。

resources

負責複制各種資源檔案,常用goal有 resources:resources ,負責将資源檔案複制到outputDirectory中,預設為${project.build.outputDirectory}。

install

負責将項目輸出(install:install)或者某個指定的檔案(install:install-file)加入到本機庫%USERPROFILE%/.m2/repository中。可以用 install:help 尋求幫助。

deploy

負責将項目輸出(deploy:deploy)或者某個指定的檔案(deploy:deploy-file)加入到公司庫中。

site

将 工程所有文檔生成網站,生成的網站界面預設和apache的項目站點類似,但是其文檔用doxia格式寫的,目前不支援docbook,需要用其他插件配 合才能支援。需要指出的是,在maven 2.x系列中和maven3.x的site指令處理是不同的,在舊版本中,用 mvn site 指令可以生成reporting節點中的所有報表,但是在maven3中,reporting過時了,要把這些内容作為 maven-site-plugin的configuration的内容才行。詳細内容可以參考http://www.wakaleo.com/blog/292-site-generation-in-maven-3

4. maven的使用問答

除了以下的幾個faq條目之外,還有一些faq可以參考

maven 自己的FAQ

兄弟們如果有其他問題,歡迎跟帖提問!

4.1 依賴關系

1) 問:如何增加删除一個依賴關系?

答:直接在pom檔案中加入一個dependency節點,如果要删除依賴,把對應的dependency節點删除即可。

2) 問:如何屏蔽一個依賴關系?比如項目中使用的libA依賴某個庫的1.0版,libB以來某個庫的2.0版,現在想統一使用2.0版,如何去掉1.0版的依賴?

答:設定exclusion即可。

    < groupId > org.hibernate </ groupId >

    < artifactId > hibernate </ artifactId >

    < version > 3.2.5.ga </ version >

    < exclusions >

        < exclusion >

            < groupId > javax.transaction </ groupId >

            < artifactId > jta </ artifactId >

        </ exclusion >

    </ exclusions >

3) 問:我有一些jar檔案要依賴,但是我又不想把這些jar去install到mvn的repository中去,怎麼做配置?

答:加入一個特殊的依賴關系,使用system類型,如下:

    < groupId > com.abc </ groupId >

    < artifactId > my-tools </ artifactId >

    < version > 2.5.0 </ version >

    < type > jar </ type >

    < scope > system </ scope >

    < systemPath > ${basedir}/lib/mylib1.jar </ systemPath >

但是要記住,釋出的時候不會複制這個jar。需要手工配置,而且其他project依賴這個project的時候,會報告警告。如果沒有特殊要求,建議直接注冊釋出到repository。

4) 問:在eclipse環境中同時使用maven builder和eclipse builder,并且設定項目依賴關系之後,為什麼編譯會出現artifact找不到錯誤,但是直接使用指令行mvn建構則一切正常?

答:在project屬性中去掉java build path中對其他 project 的依賴關系,直接在pom中設定依賴關系即可

<!-- 依賴的其他項目 -->

    < groupId > com.abc.project1 </ groupId >

    < artifactId > abc-project1-common </ artifactId >

    < version > ${project.version} </ version >

另外,保證沒有其他錯誤。

5) 問:我想讓輸出的jar包自動包含所有的依賴

答:使用 assembly 插件即可。

< plugin >

    < artifactId > maven-assembly-plugin </ artifactId >

    < configuration >

        < descriptorRefs >

            < descriptorRef > jar-with-dependencies </ descriptorRef >

        </ descriptorRefs >

    </ configuration >

</ plugin >

6) 問:我的測試用例依賴于其他工程的測試用例,如何設定?

答:maven本身在釋出的時候,可以釋出單純的jar,也可以同時釋出xxx-tests.jar和xxx-javadoc.jar(大家經常在repository中可以看到類似的東西)。我們自己的項目A要同時輸出test.jar可以做如下的設定

<!-- 用于把test代碼也做成一個jar -->

    < groupId > org.apache.maven.plugins </ groupId >

    < artifactId > maven-jar-plugin </ artifactId >

    < executions >

        < execution >

            < goals >

                < goal > test-jar </ goal >

            </ goals >

        </ execution >

    </ executions >

然後在其他需要引用的工程B中做如下的dependency設定

    < groupId > com.abc.XXX </ groupId >

    < artifactId > 工程A </ artifactId >

    < type > test-jar </ type >

    < scope > test </ scope >

7)如何讓maven将工程依賴的jar複制到WEB-INF/lib目錄下?

8)我剛剛更新了一下我的nexus庫,但是我無法在eclipse中用m2eclipse找到我新增的庫檔案

修改pom.xml檔案,将舊版jar的依賴内容中的版本直接修改為新版本即可。

9)我要的jar最新版不在maven的中央庫中,我怎麼辦?

将依賴的檔案安裝到本地庫,用如下指令可以完成:

mvn install:install-file

-Dfile=<path-to-file>

-DgroupId=<group-id>

-DartifactId=<artifact-id>

-Dversion=<version>

-Dpackaging=<packaging>

-DgeneratePom=true

Where: <path-to-file> the path to the file to load

<group-id> the group that the file should be registered under

<artifact-id> the artifact name for the file

<version> the version of the file

<packaging> the packaging of the file e.g. jar

10)

4.2 變量

1) 問:如何使用變量替換?項目中的某個配置檔案比如jdbc.properties使用了一些pom中的變量,如何在釋出中使用包含真實内容的最終結果檔案?

答:使用資源過濾功能,比如:

        < jdbc.driverClassName > com.mysql.jdbc.Driver </ jdbc.driverClassName >

        < jdbc.url > jdbc:mysql://localhost:3306/development_db </ jdbc.url >

        < jdbc.username > dev_user </ jdbc.username >

        < jdbc.password > s3cr3tw0rd </ jdbc.password >

    < build >

        < resources >

            < resource >

                < directory > src/main/resources </ directory >

                < filtering > true </ filtering >

            </ resource >

        </ resources >

    </ build >

    < profiles >

        < profile >

            < id > production </ id >

            < properties >

                < jdbc.driverClassName > oracle.jdbc.driver.OracleDriver </ jdbc.driverClassName >

                < jdbc.url > jdbc:oracle:thin:@proddb01:1521:PROD </ jdbc.url >

                < jdbc.username > prod_user </ jdbc.username >

                < jdbc.password > s00p3rs3cr3t </ jdbc.password >

            </ properties >

        </ profile >

    </ profiles >

2) 問: maven-svn-revision-number-plugin 插件說明

答: maven-svn-revision-number-plugin 可以從 SVN 中擷取版本号,并将其變成環境變量,交由其他插件或者profile使用,詳細幫助在這裡 。一般和resource的filter機制同時使用

< plugins >

    < plugin >

        < groupId > com.google.code.maven-svn-revision-number-plugin </ groupId >

        < artifactId > maven-svn-revision-number-plugin </ artifactId >

        < version > 1.3 </ version >

        < executions >

            < execution >

                < goals >

                    < goal > revision </ goal >

                </ goals >

            </ execution >

        </ executions >

        < configuration >

            < entries >

                < entry >

                    < prefix > prefix </ prefix >

                </ entry >

            </ entries >

        </ configuration >

    </ plugin >

</ plugins >

這段代碼負責把resource檔案中的内容替換成适當内容

repository = ${prefix.repository}

path = ${prefix.path}

revision = ${prefix.revision}

mixedRevisions = ${prefix.mixedRevisions}

committedRevision = ${prefix.committedRevision}

status = ${prefix.status}

specialStatus = ${prefix.specialStatus}

3)我的程式有些單元測試有錯誤,如何忽略測試步驟?

有好幾種方法都可以實作跳過單元測試步驟,一種是給mvn增加指令行參數 -Dmaven.test.skip=true 或者 -DskipTests=true ;另外一種是給surefire插件增加參數,如下:

<project> [...]

<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.8</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin> </plugins> </build> [...]</project>

4) 如果隻想運作單個測試用例,能否實作?

可以,運作時候增加指令行參數 -Dtest=MyTest 即可,其中MyTest是所需要運作的單元測試用例名稱,但是不需要包含package部分。

4.3 編譯

1) 問:如何給插件指派參數?比如我要設定一些編譯參數

答:以下内容設定編譯器編譯java1.5的代碼

        < plugins >

            < plugin >

                < artifactId > maven-compiler-plugin </ artifactId >

                < configuration >

                    < source > 1.5 </ source >

                    < target > 1.5 </ target >

                </ configuration >

            </ plugin >

        </ plugins >

要設定其他插件的參數也可以,請參考對應插件的幫助資訊

2) 問:我的目錄是非标準的目錄結構,如何設定讓maven支援?

答:指定source目錄和test-source目錄即可。

< build >

    < directory > target </ directory >

    < sourceDirectory > src </ sourceDirectory >

    < scriptSourceDirectory > js/scripts </ scriptSourceDirectory >

    < testSourceDirectory > test </ testSourceDirectory >

    < outputDirectory > bin </ outputDirectory >

    < testOutputDirectory > bin </ testOutputDirectory >

</ build >

這個例子把源代碼設定成了src目錄,測試代碼在test目錄,是以輸出到bin目錄。這裡要注意,directory如果也設定成bin目錄的 話,maven打包的時候會引起死循環,因為directory是所有工作存放的地方,預設包含outputDirectory定義的目錄在内。

3) 我源代碼是UTF8格式的,我如何在maven中指定?

設定一個變量即可

        < project.build.sourceEncoding > UTF-8 </ project.build.sourceEncoding >

{color:blue}以上是官方給出的解決方案,但是經過嘗試這樣隻能影響到resource處理時候的編碼{color},真正有用的是如下配置:

{code:xml}

<build>

...

<plugin>

<artifactId>maven-compiler-plugin</artifactId>

<configuration>

<encoding>UTF-8</encoding>

</configuration>

</plugin>

</build>

{code}

. 問:我的項目除了main/java目錄之外,還加了其他的c++目錄,想要一并編譯,如何做?

答:使用native插件,具體配置方法參考[http://mojo.codehaus.org/maven-native/native-maven-plugin/]

<groupId>org.codehaus.mojo</groupId>

<artifactId>native-maven-plugin</artifactId>

<extensions>true</extensions>

. 問:我想要把工程的所有依賴的jar都一起打包,怎麼辦?

答:首先修改maven的配置檔案,給maven-assembly-plugin增加一個jar-with-dependencies的描述。

<project>

[...]

<plugins>

<artifactId>maven-assembly-plugin</artifactId>

<descriptorRefs>

<descriptorRef>jar-with-dependencies</descriptorRef>

</descriptorRefs>

</plugins>

</project>

然後使用指令打包即可:

mvn assembly:assembly

. 問:我想把main/scripts中的内容一起打包釋出,如何做?

答:在pom中配置額外的資源目錄。如果需要的話,還可以指定資源目錄的輸出位置

<resources>

<resource>

<filtering>true</filtering>

<directory>src/main/command</directory>

<includes>

<include>run.bat</include>

<include>run.sh</include>

</includes>

<targetPath>/abc</targetPath>

</resource>

<directory>src/main/scripts</directory>

</resources>

. 問:我有多個源代碼目錄,但是maven隻支援一個main src和一個test src,怎麼辦?

答:使用另外一個插件,并仿照如下配置pom

<artifactId>build-helper-maven-plugin</artifactId>

<version>1.1</version>

<executions>

<execution>

<id>add-source</id>

<phase>generate-sources</phase>

<goals>

<goal>add-source</goal>

</goals>

<sources>

<source>src/config/java</source>

<source>src/main/java</source>

<source>src/member/java</source>

</sources>

</execution>

</executions>

. 問:我的源代碼目錄中有一部分檔案我不想讓maven編譯,怎麼做?

答:使用一個maven插件,然後使用includes和excludes。同理,也可以處理資源的過濾。

<sourceDirectory>http://www.cnblogs.com/src/java</sourceDirectory>

<groupId>com.sun.enterprise</groupId>

<artifactId>hk2-maven-plugin</artifactId>

<include>com/sun/logging/LogDomains.*</include>

<include>com/sun/enterprise/util/OS.java</include>

<include>com/sun/enterprise/util/io/FileUtils.java</include>

<include>com/sun/enterprise/util/zip/**</include>

<include>com/sun/enterprise/util/i18n/**</include>

<include>com/sun/enterprise/deployment/backend/IASDeploymentException.java</include>

<excludes>

<exclude>com/sun/enterprise/config/ConfigBeansFactory.java</exclude>

<exclude>com/sun/enterprise/config/clientbeans/**</exclude>

</excludes>

<directory>http://www.cnblogs.com/src/java</directory>

<include>**/*.properties</include>

. 問:我的項目是一個純的html組成的項目,沒有任何的java代碼,怎麼跳過編譯過程?

答:配置如下

<sourceDirectory>src/java</sourceDirectory>

. 問:我的工程裡用hibernate,想在編譯時候自動生成ddl,如何做?

答:添加插件

hibernate3-maven-plugin

,按照如下配置:

<artifactId>hibernate3-maven-plugin</artifactId>

<version>2.1</version>

<components>

<component>

<name>hbm2ddl</name>

<implementation>annotationconfiguration</implementation>

</component>

</components>

<dependencies>

<dependency>

<groupId>hsqldb</groupId>

<artifactId>hsqldb</artifactId>

<version>${hsqldb.version}</version>

</dependency>

</dependencies>

. 問:我能用maven支援eclipse RCP項目嗎?

答:當然可以,你可以使用插件 Tycho,詳細内容可以參考這裡[http://mattiasholmqvist.se/2010/02/building-with-tycho-part-1-osgi-bundles/].

<groupid>org.sonatype.tycho</groupid>

<artifactid>target-platform-configuration</artifactid>

<version>0.7.0</version>

<resolver>p2</resolver>

另外,老牌的pde-maven-plugin就不要用了,已經好幾年沒見更新了。

4.4 ant互動

1) 如何在maven編譯時候運作ant腳本?

使用專門的antrun插件,并且在target标簽内部加入ant的代碼

<plugin> <artifactId>maven-antrun-plugin</artifactId> <version>1.6</version> <executions> <execution> <phase> <!-- 生命周期階段 --> </phase> <configuration> <target> <!-- 加入target内部的代碼 --> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin>

2)如何在ant腳本中引用maven的classpath?

maven給每一個依賴都生成了一個屬性,格式為"groupId:artifactId[:classifier]:type",比如,如果一下例子就顯示依賴的org.apache.common-util的jar檔案路徑

<echo message="Dependency JAR Path: ${org.apache:common-util:jar}"/>

另外,maven還預定義了四個classpath的引用,他們是

maven.compile.classpath

maven.runtime.classpath

maven.test.classpath

maven.plugin.classpath

3)如何使用antrun插件運作外部的build檔案?

很簡單,直接在antrun裡邊使用ant指令即可,如下:

<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-antrun-plugin</artifactId> <version>1.6</version> <executions> <execution> <id>compile</id> <phase>compile</phase> <configuration> <target> <!-- 同時傳遞内置的classpath給外部ant檔案 --> <property name="compile_classpath" refid="maven.compile.classpath"/> <property name="runtime_classpath" refid="maven.runtime.classpath"/> <property name="test_classpath" refid="maven.test.classpath"/> <property name="plugin_classpath" refid="maven.plugin.classpath"/>

<ant antfile="${basedir}/build.xml"> <target name="test"/> </ant> </target> </configuration> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin>

. 問:如何在ant中使用maven的功能?

答:使用ant的[maven task|http://maven.apache.org/ant-tasks/index.html],不過隻有ant 1.6以上和jdk 1.5環境才支援。

h4. 測試相關

. 問:如何忽略某個階段的結果?比如單元測試不一定要全正确

答:給插件增加testFailureIgnore參數,并設定為false。如果要屏蔽該階段,則用

<skip>true</skip>

<groupId>org.apache.maven.plugins</groupId>

<artifactId>maven-surefire-plugin</artifactId>

<testFailureIgnore>true</testFailureIgnore>

. 問:我如何在maven中加入PMD,CheckStyle,JDepend等檢查功能?

答:加入PMD檢查,以下代碼如果在

reporting

節點中加入則在

mvn site

中執行,如果在

build

節點中加入,則在build的時候自動運作檢查。詳細配置參考[pmd插件使用說明|http://maven.apache.org/plugins/maven-pmd-plugin/]

<artifactId>maven-pmd-plugin</artifactId>

<version>2.5</version>

加入 checkstyle 檢查,詳細配置參考[checkstyle插件使用說明|http://maven.apache.org/plugins/maven- checkstyle-plugin/],同樣注意放置在reporting和build節點中的差別(所有報表類插件都要同樣注意):

<artifactId>maven-checkstyle-plugin</artifactId>

加入 simian 的支援,simian是一個支援代碼相似度檢查的工具,目前有maven插件,也有checkstyle的插件。它不僅可以檢查java,甚至可以支援文 本檔案的檢查。詳細幫助資訊參考[這裡|http://www.redhillconsulting.com.au/products/simian /]。simian 的 maven插件在[這裡|http://mojo.codehaus.org/simian-report-maven-plugin /introduction.html]

<artifactId>simian-maven-plugin</artifactId>

<version>1.6.1</version>

加入 jdepend 檢查,詳細配置參考[jdepend使用說明|http://mojo.codehaus.org/jdepend-maven-plugin/],

<artifactId>jdepend-maven-plugin</artifactId>

<version>2.0-beta-2</version>

加入 findbugz 檢查,詳細配置參考[findbugz使用說明|http://mojo.codehaus.org/findbugs-maven-plugin/usage.html],

<artifactId>findbugs-maven-plugin</artifactId>

<version>2.0.1</version>

加入javadoc生成,詳細配置參考[javadoc usage|http://maven.apache.org/plugins/maven-javadoc-plugin/usage.html]

<artifactId>maven-javadoc-plugin</artifactId>

<version>2.7</version>

加入 jxr 支援,JXR是一個生成java代碼交叉引用和源代碼的html格式的工具,詳細配置資訊參考[jxr usage|http://maven.apache.org/plugins/maven-jxr-plugin/]。注意,jxr沒有必要在 build階段運作。

<reporting>

<artifactId>maven-jxr-plugin</artifactId>

</reporting>

加入 Cobertura 支援,它是一個代碼覆寫率工具,可以用來評估具有相應測試的源代碼的比率。詳細幫助在[這裡|http://mojo.codehaus.org /cobertura-maven-plugin/index.html]。另外一個功能相似的軟體是[EMMA|http: //emma.sourceforge.net/samples.html],詳細的幫助在[這裡|http://mojo.codehaus.org /emma-maven-plugin/usage.html]。兩個産品的比較文章在[這裡|http://www.topcoder.com /tc?module=Static&d1=features&d2=030107],個人傾向于都要用,因為給出的名額不一樣,都有參 考作用。

{code:xml|title=Cobertura }

<artifactId>cobertura-maven-plugin</artifactId>

<version>2.4</version>

<check>

<branchRate>85</branchRate>

<lineRate>85</lineRate>

<haltOnFailure>true</haltOnFailure>

<totalBranchRate>85</totalBranchRate>

<totalLineRate>85</totalLineRate>

<packageLineRate>85</packageLineRate>

<packageBranchRate>85</packageBranchRate>

<regexes>

<regex>

<pattern>com.example.reallyimportant.*</pattern>

<branchRate>90</branchRate>

<lineRate>80</lineRate>

</regex>

<pattern>com.example.boringcode.*</pattern>

<branchRate>40</branchRate>

<lineRate>30</lineRate>

</regexes>

</check>

<goal>clean</goal>

<goal>check</goal>

{code:xml|title=EMMA}

<artifactId>emma-maven-plugin</artifactId>

<version>1.0-alpha-3-SNAPSHOT</version>

添加 javaNCSS 插件,它是一個java代碼的度量工具,詳細參考在[這裡|http://mojo.codehaus.org/javancss-maven-plugin/]。

<artifactId>javancss-maven-plugin</artifactId>

h4. profile相關

. 問:profile能夠設定為某個變量不存在的條件下激活?

答:使用!字首,請看示例:

<activation>

<property>

<name>!environment.type</name>

</property>

</activation>

h4. 部署相關

. 問:其他部署到伺服器的方式和配置怎麼配?

答:本文摘自 [http://blog.csdn.net/zyxnetxz/archive/2009/05/18/4199348.aspx]{panel} *Distribution Management* 用于配置分發管理,配置相應的産品釋出資訊,主要用于釋出,在執行mvn deploy後表示要釋出的位置 *# 配置到檔案系統

<distributionManagement>

<repository>

<id>proficio-repository<id>

<name>Proficio Repository<name>

<url>file://${basedir}/target/deploy<url>

*# 使用ssh2配置

<url>scp://sshserver.yourcompany.com/deploy<url>

*# 使用sftp配置

<id>proficio-repositoryi<d>

<url>sftp://ftpserver.yourcompany.com/deploy<url>

*# 使用外在的ssh配置編譯擴充用于指定使用wagon外在ssh提供,用于提供你的檔案到相應的遠端伺服器。

<url>scpexe://sshserver.yourcompany.com/deploy<url>

<extensions>

<extension>

<groupId>org.apache.maven.wagon<groupId>

<artifactId>wagon-ssh-external<artifactId>

<version>1.0-alpha-6<version>

*# 使用ftp配置

<url>ftp://ftpserver.yourcompany.com/deploy<url>

<groupId>org.apache.maven.wagongroupId>

<artifactId>wagon-ftpartifactId>

<version>1.0-alpha-6version>

{panel} h4. 插件配置

. 問:我用maven輸出site,如何設定輸出為utf8編碼?

答: 配置site插件的編碼設定

<artifactId>maven-site-plugin</artifactId>

<version>2.0-beta-6</version>

<outputEncoding>UTF-8</outputEncoding>

若轉載請注明出處!若有疑問,請回複交流!