前言 Maven,發(fā)音是[`meivin],專家的意思。它是一個(gè)很好的項(xiàng)目管理工具,很早就進(jìn)入了我的必備工具行列,但是這次為了把ABPM項(xiàng)目 完全遷移并應(yīng)用maven,所以對(duì)maven進(jìn)行了一些深入的學(xué)習(xí)。寫這個(gè)學(xué)習(xí)筆記的目的,一個(gè)是為了自己備忘,二則希望能夠?yàn)槠渌?/p>
Maven,發(fā)音是[`meivin],"專家"的意思。它是一個(gè)很好的項(xiàng)目管理工具,很早就進(jìn)入了我的必備工具行列,但是這次為了把ABPM項(xiàng)目 完全遷移并應(yīng)用maven,所以對(duì)maven進(jìn)行了一些深入的學(xué)習(xí)。寫這個(gè)學(xué)習(xí)筆記的目的,一個(gè)是為了自己備忘,二則希望能夠?yàn)槠渌藢W(xué)習(xí)使用maven 縮短一些時(shí)間。
首先我把maven的概念快速的梳理一下,讓我們快速地建立起一個(gè)比較精確的maven應(yīng)用場(chǎng)景。
讀書時(shí)候要先限定范圍,避免一些有害的遐想。要說maven不是什么,我們可以從如下幾個(gè)要點(diǎn)來展開
maven將自己定位為一個(gè)項(xiàng)目管理工具。它負(fù)責(zé)管理項(xiàng)目開發(fā)過程中的幾乎所有的東西:
maven把項(xiàng)目的構(gòu)建劃分為不同的生命周期(lifecycle),在我看來,劃分的已經(jīng)是非常仔細(xì)了,大家可以參考這里 。粗略一點(diǎn)的話,它這個(gè)過程(phase)包括:編譯、測(cè)試、打包、集成測(cè)試、驗(yàn)證、部署。maven中所有的執(zhí)行動(dòng)作(goal)都需要指明自己在這個(gè)過程中的執(zhí)行位置,然后maven執(zhí)行的時(shí)候,就依照過程的發(fā)展依次調(diào)用這些goal進(jìn)行各種處理。
這個(gè)也是maven的一個(gè)基本調(diào)度機(jī)制。一般來說,位置稍后的過程都會(huì)依賴于之前的過程。當(dāng)然,maven同樣提供了配置文件,可以依照用戶要求,跳過某些階段。
所謂的"約定優(yōu)于配置",在maven中并不是完全不可以修改的,他們只是一些配置的默認(rèn)值而已。但是使用者除非必要,并不需要去修改那些約定內(nèi)容。maven默認(rèn)的文件存放結(jié)構(gòu)如下:
每一個(gè)階段的任務(wù)都知道怎么正確完成自己的工作,比如compile任務(wù)就知道從src/main/java下編譯所有的java文件,并把它的輸出class文件存放到target/classes中。
對(duì)maven來說,采用"約定優(yōu)于配置"的策略可以減少修改配置的工作量,也可以降低學(xué)習(xí)成本,更重要的是,給項(xiàng)目引入了統(tǒng)一的規(guī)范。
maven使用如下幾個(gè)要素來唯一定位某一個(gè)輸出物: groupId:artifactId:packaging:version 。比如org.springframework:spring:2.5 。每個(gè)部分的解釋如下:
maven有自己的版本規(guī)范,一般是如下定義
maven在版本管理時(shí)候可以使用幾個(gè)特殊的字符串 SNAPSHOT ,LATEST ,RELEASE 。比如"1.0-SNAPSHOT"。各個(gè)部分的含義和處理邏輯如下說明:
maven把整個(gè)maven管理的項(xiàng)目分為幾個(gè)部分,一個(gè)部分是源代碼,包括源代碼本身、相關(guān)的各種資源,一個(gè)部分則是單元測(cè)試用例,另外一部分則是各種maven的插件。對(duì)于這幾個(gè)部分,maven可以獨(dú)立管理他們,包括各種外部依賴關(guān)系。
依賴管理一般是最吸引人使用maven的功能特性了,這個(gè)特性讓開發(fā)者只需要關(guān)注代碼的直接依賴,比如我們用了spring,就加入spring依賴說明就可以了,至于spring自己還依賴哪些外部的東西,maven幫我們搞定。
任意一個(gè)外部依賴說明包含如下幾個(gè)要素:groupId, artifactId, version, scope, type, optional。其中前3個(gè)是必須的,各自含義如下:
maven認(rèn)為,程序?qū)ν獠康囊蕾嚂?huì)隨著程序的所處階段和應(yīng)用場(chǎng)景而變化,所以maven中的依賴關(guān)系有作用域(scope)的限制。在maven中,scope包含如下的取值:
另外,代碼有代碼自己的依賴,各個(gè)maven使用的插件也可以有自己的依賴關(guān)系。依賴也可以是可選的,比如我們代碼中沒有任何cache依賴,但是hibernate可能要配置cache,所以該cache的依賴就是可選的。
maven的多項(xiàng)目管理也是非常強(qiáng)大的。一般來說,maven要求同一個(gè)工程的所有子項(xiàng)目都放置到同一個(gè)目錄下,每一個(gè)子目錄代表一個(gè)項(xiàng)目,比如
按照這種格式存放,就是繼承方式,所有具體子項(xiàng)目的pom.xml都會(huì)繼承總項(xiàng)目pom的內(nèi)容,取值為子項(xiàng)目pom內(nèi)容優(yōu)先。
要設(shè)置繼承方式,首先要在總項(xiàng)目的pom中加入如下配置
Xml代碼
其次在每個(gè)子項(xiàng)目中加入
org.sonatype.mavenbook.ch06 simple-parent1.0
即可。
當(dāng)然,繼承不是唯一的配置文件共用方式,maven還支持引用方式。引用pom的方式更簡(jiǎn)單,在依賴中加入一個(gè)type為pom的依賴即可。
Xml代碼
用戶可以在maven中定義一些屬性,然后在其他地方用${xxx}進(jìn)行引用。比如:
Xml代碼
maven提供了三個(gè)隱式的變量,用來訪問系統(tǒng)環(huán)境變量、POM信息和maven的settings:
profile是maven的一個(gè)重要特性,它可以讓maven能夠自動(dòng)適應(yīng)外部的環(huán)境變化,比如同一個(gè)項(xiàng)目,在linux下編譯linux的版 本,在win下編譯win的版本等。一個(gè)項(xiàng)目可以設(shè)置多個(gè)profile,也可以在同一時(shí)間設(shè)置多個(gè)profile被激活(active)的。自動(dòng)激活的 profile的條件可以是各種各樣的設(shè)定條件,組合放置在activation節(jié)點(diǎn)中,也可以通過命令行直接指定。profile包含的其他配置內(nèi)容可 以覆蓋掉pom定義的相應(yīng)值。如果認(rèn)為profile設(shè)置比較復(fù)雜,可以將所有的profiles內(nèi)容移動(dòng)到專門的 profiles.xml 文件中,不過記得和pom.xml放在一起。
activation節(jié)點(diǎn)中的激活條件中常見的有如下幾個(gè):
maven的操作有兩種方式,一種是通過mvn命令行命令,一種是使用maven的eclipse插件。因?yàn)槭褂胑clipse的maven插件操作起來比較容易,這里就只介紹使用mvn命令行的操作。
maven的主執(zhí)行程序?yàn)閙vn.bat,linux下為mvn.sh,這兩個(gè)程序都很簡(jiǎn)單,它們的共同用途就是收集一些參數(shù),然后用 java.exe來運(yùn)行maven的Main函數(shù)。maven同樣需要有配置文件,名字叫做settings.xml,它放在兩個(gè)地方,一個(gè)是maven 安裝目錄的conf目錄下,對(duì)所有使用該maven的用戶都起作用,我們稱為主配置文件,另外一個(gè)放在 %USERPROFILE%/.m2/settings.xml下,我們成為用戶配置文件,只對(duì)當(dāng)前用戶有效,且可以覆蓋主配置文件的參數(shù)內(nèi)容。還有就是 項(xiàng)目級(jí)別的配置信息了,它存放在每一個(gè)maven管理的項(xiàng)目目錄下,叫pom.xml,主要用于配置項(xiàng)目相關(guān)的一些內(nèi)容,當(dāng)然,如果有必要,用戶也可以在 pom中寫一些配置,覆蓋住配置文件和用戶配置文件的設(shè)置參數(shù)內(nèi)容。
一般來說,settings文件配置的是比如repository庫(kù)路徑之類的全局信息,具體可以參考官方網(wǎng)站的文章 。
要?jiǎng)?chuàng)建一個(gè)新的maven工程,我們需要給我們的工程指定幾個(gè)必要的要素,就是maven產(chǎn)品坐標(biāo)的幾個(gè)要素:groupId, artifactId,如果愿意,你也可以指定version和package名稱。我們先看一個(gè)簡(jiǎn)單的創(chuàng)建命令:
d:\work\temp>mvn archetype:create -DgroupId=com.abc -DartifactId=product1 -DarchetypeArtifactId=maven-archetype-webapp
首先看這里的命令行參數(shù)的傳遞結(jié)構(gòu),怪異的 -D參數(shù)=值 的方式是 java.exe 要求的方式。這個(gè)命令創(chuàng)建一個(gè)web工程,目錄結(jié)構(gòu)是一個(gè)標(biāo)準(zhǔn)的maven結(jié)構(gòu),如下:
D:. └─mywebapp │ pom.xml │ └─src └─main ├─resources └─webapp │ index.jsp │ └─WEB-INF web.xml
大家要注意,這里目錄結(jié)構(gòu)的布局實(shí)際上是由參數(shù) archetypeArtifactId 來決定的,因?yàn)檫@里傳入的是 maven-archetype-webapp如果我們傳入其他的就會(huì)創(chuàng)建不同的結(jié)構(gòu),默認(rèn)值為 maven-archetype-quickstart ,有興趣的讀者可以參考更詳細(xì)的列表 ,我把部分常用的列表在這里:
Artifact Group Version Repository Descriptionmaven-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 |
大家可以參考更詳細(xì)的 archetype:create 幫助 和 archtype參考信息 。
多項(xiàng)目管理是maven的主要特色之一,對(duì)于一個(gè)大型工程,用maven來管理他們之間復(fù)雜的依賴關(guān)系,是再好不過了。maven的項(xiàng)目配置之間的關(guān)系有兩種:繼承關(guān)系和引用關(guān)系。
maven默認(rèn)根據(jù)目錄結(jié)構(gòu)來設(shè)定pom的繼承關(guān)系,即下級(jí)目錄的pom默認(rèn)繼承上級(jí)目錄的pom。要設(shè)定兩者之間的關(guān)系很簡(jiǎn)單,上級(jí)pom如下設(shè)置:
Xml代碼
要記住的是,這里的module是目錄名,不是子工程的artifactId。子工程如下設(shè)置:
Xml代碼
這樣兩者就相互關(guān)聯(lián)起來了,繼承關(guān)系就設(shè)定完畢,所有父工程的配置內(nèi)容都會(huì)自動(dòng)在子工程中生效,除非子工程有相同的配置覆蓋。如果你不喜歡層層遞進(jìn)的目錄結(jié)構(gòu)來實(shí)現(xiàn)繼承,也可以在parent中加入
引用關(guān)系是另外一種復(fù)用的方式,maven中配置引用關(guān)系也很簡(jiǎn)單,加入一個(gè) type 為 pom 的依賴即可。
Xml代碼
但是無論是父項(xiàng)目還是引用項(xiàng)目,這些工程都必須用 mvn install 或者 mvn deploy 安裝到本地庫(kù)才行,否則會(huì)報(bào)告依賴沒有找到,eclipse編譯時(shí)候也會(huì)出錯(cuò)。
需要特別提出的是復(fù)用過程中,父項(xiàng)目的pom中可以定義 dependencyManagement 節(jié)點(diǎn),其中存放依賴關(guān)系,但是這個(gè)依賴關(guān)系只是定義,不會(huì)真的產(chǎn)生效果,如果子項(xiàng)目想要使用這個(gè)依賴關(guān)系,可以在本身的 dependency 中添加一個(gè)簡(jiǎn)化的引用
Xml代碼
這種方法可以避免版本號(hào)滿天飛的情況。
在maven中一般都會(huì)用到安裝庫(kù)文件的功能,一則是我們常用的hibernate要使用jmx庫(kù),但是因?yàn)閟un的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://aaa.ss.com/ss.xxx -DrepositoryId=release-repo
對(duì)于我們的工程輸出,如果需要放置到公司的repository中的話,可以通過配置pom來實(shí)現(xiàn)
Xml代碼
這里使用的scp方式提交庫(kù)文件,還有其他方式可以使用,請(qǐng)參考faq部分。然后記得在你的settings.xml中加入這一內(nèi)容
Xml代碼
maven定義了很多變量屬性,參考這里 http://docs.codehaus.org/display/MAVENUSER/MavenPropertiesGuide
... ... hello
我們已經(jīng)知道m(xù)aven預(yù)定義了許多的階段(phase),每個(gè)插件都依附于這些階段,并且在進(jìn)入某個(gè)階段的時(shí)候,調(diào)用運(yùn)行這些相關(guān)插件的功能。我們先來看完整的maven生命周期:
生命周期 階段描述validate | 驗(yàn)證項(xiàng)目是否正確,以及所有為了完整構(gòu)建必要的信息是否可用 |
generate-sources | 生成所有需要包含在編譯過程中的源代碼 |
process-sources | 處理源代碼,比如過濾一些值 |
generate-resources | 生成所有需要包含在打包過程中的資源文件 |
process-resources | 復(fù)制并處理資源文件至目標(biāo)目錄,準(zhǔn)備打包 |
compile | 編譯項(xiàng)目的源代碼 |
process-classes | 后處理編譯生成的文件,例如對(duì)Java類進(jìn)行字節(jié)碼增強(qiáng)(bytecode enhancement) |
generate-test-sources | 生成所有包含在測(cè)試編譯過程中的測(cè)試源碼 |
process-test-sources | 處理測(cè)試源碼,比如過濾一些值 |
generate-test-resources | 生成測(cè)試需要的資源文件 |
process-test-resources | 復(fù)制并處理測(cè)試資源文件至測(cè)試目標(biāo)目錄 |
test-compile | 編譯測(cè)試源碼至測(cè)試目標(biāo)目錄 |
test | 使用合適的單元測(cè)試框架運(yùn)行測(cè)試。這些測(cè)試應(yīng)該不需要代碼被打包或發(fā)布 |
prepare-package | 在真正的打包之前,執(zhí)行一些準(zhǔn)備打包必要的操作。這通常會(huì)產(chǎn)生一個(gè)包的展開的處理過的版本(將會(huì)在Maven 2.1+中實(shí)現(xiàn)) |
package | 將編譯好的代碼打包成可分發(fā)的格式,如JAR,WAR,或者EAR |
pre-integration-test | 執(zhí)行一些在集成測(cè)試運(yùn)行之前需要的動(dòng)作。如建立集成測(cè)試需要的環(huán)境 |
integration-test | 如果有必要的話,處理包并發(fā)布至集成測(cè)試可以運(yùn)行的環(huán)境 |
post-integration-test | 執(zhí)行一些在集成測(cè)試運(yùn)行之后需要的動(dòng)作。如清理集成測(cè)試環(huán)境。 |
verify | 執(zhí)行所有檢查,驗(yàn)證包是有效的,符合質(zhì)量規(guī)范 |
install | 安裝包至本地倉(cāng)庫(kù),以備本地的其它項(xiàng)目作為依賴使用 |
deploy | 復(fù)制最終的包至遠(yuǎn)程倉(cāng)庫(kù),共享給其它開發(fā)人員和項(xiàng)目(通常和一次正式的發(fā)布相關(guān)) |
maven核心的插件列表可以參考 http://maven.apache.org/plugins/index.html 。這里僅列舉幾個(gè)常用的插件及其配置參數(shù):
除了以下的幾個(gè)faq條目之外,還有一些faq可以參考
兄弟們?nèi)绻衅渌麊栴},歡迎跟帖提問!
答:直接在pom文件中加入一個(gè)dependency節(jié)點(diǎn),如果要?jiǎng)h除依賴,把對(duì)應(yīng)的dependency節(jié)點(diǎn)刪除即可。
答:設(shè)置exclusion即可。
Xml代碼
答:加入一個(gè)特殊的依賴關(guān)系,使用system類型,如下:
com.abc my-tools2.5.0 jar system ${basedir}/lib/mylib1.jar
但是要記住,發(fā)布的時(shí)候不會(huì)復(fù)制這個(gè)jar。需要手工配置,而且其他project依賴這個(gè)project的時(shí)候,會(huì)報(bào)告警告。如果沒有特殊要求,建議直接注冊(cè)發(fā)布到repository。
答:在project屬性中去掉java build path中對(duì)其他 project 的依賴關(guān)系,直接在pom中設(shè)置依賴關(guān)系即可
com.abc.project1 abc-project1-common${project.version}
另外,保證沒有其他錯(cuò)誤。
答:使用 assembly 插件即可。
maven-assembly-plugin jar-with-dependencies
答:maven本身在發(fā)布的時(shí)候,可以發(fā)布單純的jar,也可以同時(shí)發(fā)布xxx-tests.jar和xxx-javadoc.jar(大家經(jīng)常在repository中可以看到類似的東西)。我們自己的項(xiàng)目A要同時(shí)輸出test.jar可以做如下的設(shè)置
org.apache.maven.plugins maven-jar-plugintest-jar
然后在其他需要引用的工程B中做如下的dependency設(shè)置
Xml代碼
答:使用資源過濾功能,比如:
.. .. com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/development_db dev_user s3cr3tw0rd .. src/main/resources true production oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@proddb01:1521:PROD prod_user s00p3rs3cr3t
答: maven-svn-revision-number-plugin 可以從 SVN 中獲取版本號(hào),并將其變成環(huán)境變量,交由其他插件或者profile使用,詳細(xì)幫助在這里 。一般和resource的filter機(jī)制同時(shí)使用
com.google.code.maven-svn-revision-number-plugin maven-svn-revision-number-plugin1.3 revision prefix
這段代碼負(fù)責(zé)把resource文件中的內(nèi)容替換成適當(dāng)內(nèi)容
repository = ${prefix.repository} path = ${prefix.path} revision = ${prefix.revision} mixedRevisions = ${prefix.mixedRevisions} committedRevision = ${prefix.committedRevision} status = ${prefix.status} specialStatus = ${prefix.specialStatus}
答:以下內(nèi)容設(shè)定編譯器編譯java1.5的代碼
... ... ...... maven-compiler-plugin 1.5 1.5
要設(shè)置其他插件的參數(shù)也可以,請(qǐng)參考對(duì)應(yīng)插件的幫助信息
答:指定source目錄和test-source目錄即可。
target src
這個(gè)例子把源代碼設(shè)置成了src目錄,測(cè)試代碼在test目錄,所以輸出到bin目錄。這里要注意,directory如果也設(shè)置成bin目錄的 話,maven打包的時(shí)候會(huì)引起死循環(huán),因?yàn)閐irectory是所有工作存放的地方,默認(rèn)包含outputDirectory定義的目錄在內(nèi)。
http://www.iteye.com/topic/973166
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com