本書代碼下載下傳
大家可以從我的網站下載下傳本書的代碼:http://www.juvenxu.com/mvn-in-action/,也可以通過我的網站與我取得聯系,歡迎大家與我交流任何關于本書的問題和關于Maven的問題。
咖啡與工具
本書相當一部分的内容是在蘇州十全街邊的Solo咖啡館完成的,老闆Yin親手烘焙咖啡豆、并能做出據說是蘇州最好的咖啡,這小橋流水畔的溫馨小 屋能夠幫我消除緊張和焦慮,和Yin有一句沒一句的聊天也是相當的輕松。Yin還教會了我如何自己研磨咖啡豆、手沖滴率咖啡,讓我能夠每天在家裡也能享受 香氣四溢的新鮮咖啡。
本書的書稿是使用Git和Unfuddle(http://unfuddle.com/)進行管理的,書中的大量截圖是通過Jing(http://www.techsmith.com/jing/)制作的。
JuvenXu
2010年10月于蘇州Solo咖啡
緻謝
感謝費曉峰,是你最早讓我學習使用Maven,并在我開始學習的過程中給予了不少幫助。
感謝Maven開源社群特别是Maven的創立者Jason Van Zyl,是你們一起創造了如此優秀的開源工具,造福了全世界這麼多的開發人員。
感謝我的家人,一年來,我的大部分原來屬于你們的業餘時間都給了這本書,感謝你們的了解和支援。
感謝二少、Garin、Sutra、JTux、紅人、linux_china、Chris、Jdonee、zc0922、還有很多Maven中文社群的朋友,你們給了本書不少建議,并在我寫作過程中不斷鼓勵我和支援我,你們是我寫作最大的動力之一。
最後感謝本書的策劃編輯楊福川和曾珊,我從你們身上學到了很多,你們是最專業的、最棒的。
第1章 Maven簡介
1.1 何為Maven/2
1.2 為什麼需要Maven/4
1.3 Maven與極限程式設計/7
1.4 被誤解的Maven/8
1.5 小結/9
1.1 何為Maven
Maven這個詞可以翻譯為“知識的積累”,也可以翻譯為“專 家”或“内行”。本書将介紹Maven這一跨平台的項目管理工具。作為Apache組織中的一個頗為成功的開源項目,Maven主要服務于基于Java平 台的項目建構、依賴管理和項目資訊管理。無論是小型的開源類庫項目,還是大型的企業級應用;無論是傳統的瀑布式開發,還是流行的靈活模式,Maven都能 大顯身手。
1.1.1 何為建構
不管你是否意識到,建構(build)是每一位程式員每天都在做的工作。早上來 到公司,我們做的第一件事情就是從源碼庫簽出最新的源碼,然後進行單元測試,如果發現失敗的測試,會找相關的同僚一起調試,修複錯誤代碼。接着回到自己的 工作上來,編寫自己的單元測試及産品代碼,我們會感激IDE随時報出的編譯錯誤提示。
忙到午飯時間,代碼編寫得差不多了,測試也通過了,開心地享 用午餐,然後休息。下午先在昏昏沉沉中開了個例會,會議結束後喝杯咖啡繼續工作。剛才在會上經理要求看測試報告,于是找了相關工具內建進IDE,生成了像 模像樣的測試覆寫率報告,接着發了一封電子郵件給經理,松了口氣。誰料QA小組又發過來了幾個bug,沒辦法,先本地重制再說,于是熟練地用IDE生成了 一個WAR包,部署到Web容器下,啟動容器。看到熟悉的界面了,遵循bug報告,一步步重制了bug……快下班的時候,bug修好了,送出代碼,通知 QA小組,在愉快中結束了一天的工作。
仔細總結一下,我們會發現,除了編寫源代碼,我們每天有相當一部分時間花在了編 譯、運作單元測試、生成文檔、打包和部署等煩瑣且不起眼的工作上,這就是建構。如果我們現在還手工這樣做,那成本也太高了,于是有人用軟體的方法讓這一系 列工作完全自動化,使得軟體的建構可以像全自動流水線一樣,隻需要一條簡單的指令,所有煩瑣的步驟都能夠自動完成,很快就能得到最終結果。
1.1.2 Maven是優秀的建構工具
前面介紹了Maven的用途之一是服務于建構,它是一個異常強大的建構工具,能 夠幫我們自動化建構過程,從清理、編譯、測試到生成報告,再到打包和部署。我們不需要也不應該一遍又一遍地輸入指令,一次又一次地點選滑鼠,我們要做的是 使用Maven配置好項目,然後輸入簡單的指令(如mvn clean install),Maven會幫我們處理那些煩瑣的任務。
Maven是跨平台的,這意味着無論是在Windows上,還是在Linux或者Mac上,都可以使用同樣的指令。
我們一直在不停地尋找避免重複的方法。設計的重複、編碼的重複、文檔的重複,當 然還有建構的重複。Maven最大化地消除了建構的重複,抽象了建構生命周期,并且為絕大部分的建構任務提供了已實作的插件,我們不再需要定義過程,甚至 不需要再去實作這些過程中的一些任務。最簡單的例子是測試,我們沒必要告訴Maven去測試,更不需要告訴Maven如何運作測試,隻需要遵循Maven 的約定編寫好測試用例,當我們運作建構的時候,這些測試便會自動運作。
想象一下,Maven抽象了一個完整的建構生命周期模型,這個模型吸取了大量其 他的建構腳本和建構工具的優點,總結了大量項目的實際需求。如果遵循這個模型,可以避免很多不必要的錯誤,可以直接使用大量成熟的Maven插件來完成我 們的任務(很多時候我們可能都不知道自己在使用Maven插件)。此外,如果有非常特殊的需求,我們也可以輕松實作自己的插件。
Maven還有一個優點,它能幫助我們标準化建構過程。在Maven之前,十個項目可能有十種建構方式;有了Maven之後,所有項目的建構指令都是簡單一緻的,這極大地避免了不必要的學習成本,而且有利于促進項目團隊的标準化。
綜上所述,Maven作為一個建構工具,不僅能幫我們自動化建構,還能夠抽象建構過程,提供建構任務實作;它跨平台,對外提供了一緻的操作接口,這一切足以使它成為優秀的、流行的建構工具。
1.1.3 Maven不僅僅是建構工具
Java不僅是一門程式設計語言,還是一個平台,通過JRuby和Jython,我 們可以在Java平台上編寫和運作Ruby和Python程式。我們也應該認識到,Maven不僅是建構工具,還是一個依賴管理工具和項目資訊管理工具。 它提供了中間倉庫,能幫我們自動下載下傳構件。
在這個開源的年代裡,幾乎任何Java應用都會借用一些第三方的開源類庫,這些 類庫都可通過依賴的方式引入到項目中來。随着依賴的增多,版本不一緻、版本沖突、依賴臃腫等問題都會接踵而來。手工解決這些問題是十分枯燥的,幸運的是 Maven提供了一個優秀的解決方案,它通過一個坐标系統準确地定位每一個構件(artifact),也就是通過一組坐标Maven能夠找到任何一個 Java類庫(如jar檔案)。Maven給這個類庫世界引入了經緯,讓它們變得有秩序,于是我們可以借助它來有序地管理依賴,輕松地解決那些繁雜的依賴 問題。
Maven還能幫助我們管理原本分散在項目中各個角落的項目資訊,包括項目描 述、開發者清單、版本控制系統位址、許可證、缺陷管理系統位址等。這些微小的變化看起來很瑣碎,并不起眼,但卻在不知不覺中為我們節省了大量尋找資訊的時 間。除了直接的項目資訊,通過Maven自動生成的站點,以及一些已有的插件,我們還能夠輕松獲得項目文檔、測試報告、靜态分析報告、源碼版本日志報告等 非常具有價值的項目資訊。
Maven還為全世界的Java開發者提供了一個免費的中間倉庫,在其中幾乎可以找到任何的流行開源類庫。通過一些Maven的衍生工具(如Nexus),我們還能對其進行快速地搜尋。隻要定位了坐标,Maven就能夠幫我們自動下載下傳,省去了手工勞動。
使用Maven還能享受一個額外的好處,即Maven對于項目目錄結構、測試用 例命名方式等内容都有既定的規則,隻要遵循了這些成熟的規則,使用者在項目間切換的時候就免去了額外的學習成本,可以說是約定優于配置 (Convention Over Configuration)。
1.2 為什麼需要Maven
Maven不是Java領域唯一的建構管理的解決方案。本節将通過一些簡單的例子解釋Maven的必要性,并介紹其他建構解決方案,如IDE、Make和Ant,并将它們與Maven進行比較。
1.2.1 組裝PC和品牌PC
筆者國中時開始接觸計算機,到了高中時更是夢寐以求希望擁有一台自己的計算機。我的第一台計算機是賽揚733的,選購是一個漫長的過程,我先閱讀了大量的雜志以了解各類配件的優劣,CPU、記憶體、主機闆、顯示卡,甚至聲霸卡,我都仔細地挑選,後來還跑了很多商家,調貨、讨價還價,組裝好後自己裝作業系統和驅動程式……雖然這花費了我大量時間,但我很享受這個過程。可是事實證明,裝出來的機器穩定性不怎麼好。
一年前我需要配一台工作站,這時候我已經沒有太多時間去研究電腦配件了。我選擇了某知名PC供應商的線上商店,大概浏覽了一下主流的機型,選擇了我需要的配置,然後下單、付款。接着PC供應商幫我組裝電腦、安裝作業系統和驅動程式。一周後,物流公司将電腦送到我的家裡,我接上顯示器、電源、滑鼠和鍵盤就能直接使用了。這為我節省了大量時間,而且這台電腦十分穩定,商家在把電腦發送給我之前已經進行了很好的測試。對了,我還能享受兩年的售後服務。
使用腳本建立高度自定義的建構系統就像買組裝PC,耗時費力,結果也不一定很好。當然,你可以享受從無到有的樂趣,但恐怕實際項目中無法給你那麼多時間。使用Maven就像購買品牌PC,省時省力,并能得到成熟的建構系統,還能得到來自于Maven社群的大量支援。唯一與購買品牌PC不同的是,Maven是開源的,你無須為此付費。如果有興趣,你還能去了解Maven是如何工作的,而我們無法知道那些PC巨頭的商業秘密。
1.2.2 IDE不是萬能的
當然,我們無法否認優秀的IDE能大大提高開發效率。目前主流的IDE如Eclipse和NetBeans等都提供了強大的文本編輯、調試甚至重構功能。雖然使用簡單的文本編輯器和指令行也能完成絕大部分開發工作,但很少有人願意那樣做。然而,IDE是有其天生缺陷的:
- IDE依賴大量的手工操作。編譯、測試、代碼生成等工作都是互相獨立的,很難一鍵完成所有工作。手工勞動往往意味着低效,意味着容易出錯。
- 很難在項目中統一所有的IDE配置,每個人都有自己的喜好。也正是由于這個原因,一個在機器A上可以成功運作的任務,到了機器B的IDE中可能就會失敗。
我們應該合理利用IDE,而不是過多地依賴它。對于建構這樣的任務,在IDE中一次次地點選滑鼠是愚蠢的行為。Maven是這方面的專家,而且主流IDE都內建了Maven,我們可以在IDE中友善地運作Maven執行建構。
1.2.3 Make
Make也許是最早的建構工具,它由Stuart Feldman于1977年在Bell實驗室建立。Stuart Feldman也是以于2003年獲得了ACM國際計算機組織頒發的軟體系統獎。目前Make有很多衍生實作,包括最流行的GNU Make和BSD Make,還有Windows平台的Microsoft nmake等。
Make由一個名為Makefile的腳本檔案驅動,該檔案使用Make自己定義的文法格式。其基本組成部分為一系列規則(Rules),而每一條規則又包括目标(Target)、依賴(Prerequisite)和指令(Command)。Makefile的基本結構如下:
- <span style="font-size: small;">TARGET… : PREREQUISITE…
- COMMAND
- …
- …
- </span>
Make通過一系列目标和依賴将整個建構過程串聯起來,同時利用本地指令完成每個目标的實際行為。Make的強大之處在于它可以利用所有系統的本地指令,尤其是UNIX/Linux系統,豐富的功能、強大的指令能夠幫助Make快速高效地完成任務。
但是,Make将自己和作業系統綁定在一起了。也就是說,使用Make,就不能實作(至少很難)跨平台的建構,這對于Java來說是非常不友好的。此外,Makefile的文法也成問題,很多人抱怨Make建構失敗的原因往往是一個難以發現的空格或Tab使用錯誤。
1.2.4 Ant
Ant不是指螞蟻,而是意指“另一個整潔的工具”(Another Neat Tool),它最早用來建構著名的Tomcat,其作者James Duncan Davidson創作它的動機就是因為受不了Makefile的文法格式。我們可以将Ant看成是一個Java版本的Make,也正因為使用了Java,Ant是跨平台的。此外,Ant使用XML定義建構腳本,相對于Makefile來說,這也更加友好。
與Make類似,Ant有一個建構腳本build.xml,如下所示:
<?xml version="1.0"?>
<project name="Hello" default="compile">
<target name="compile" description="compile the Java source code to class files">
<mkdir dir="classes"/>
<javac srcdir="." destdir="classes"/>
</target>
<target name="jar" depends="compile" description="create a Jar file ">
<jar destfile="hello.jar">
<fileset dir="classes" includes="**/*.class"/>
<manifest>
<attribute name="Main.Class" value="HelloProgram"/>
</manifest>
</jar>
</target>
</project>
build.xml的基本結構也是目标(target)、依賴(depends),以及實作目标的任務。比如在上面的腳本中,jar目标用來建立應用程式jar檔案,該目标依賴于compile目标,後者執行的任務是建立一個名為classes的檔案夾,編譯目前目錄的java檔案至classes目錄。compile目标完成後,jar目标再執行自己的任務。Ant有大量内置的用Java實作的任務,這保證了其跨平台的特質,同時,Ant也有特殊的任務exec來執行本地指令。
和Make一樣,Ant也都是過程式的,開發者顯式地指定每一個目标,以及完成該目标所需要執行的任務。針對每一個項目,開發者都需要重新編寫這一過程,這裡其實隐含着很大的重複。Maven是聲明式的,項目建構過程和過程各個階段所需的工作都由插件實作,并且大部分插件都是現成的,開發者隻需要聲明項目的基本元素,Maven就執行内置的、完整的建構過程。這在很大程度上消除了重複。
Ant是沒有依賴管理的,是以很長一段時間Ant使用者都不得不手工管理依賴,這是一個令人頭疼的問題。幸運的是,Ant使用者現在可以借助Ivy管理依賴。而對于Maven使用者來說,依賴管理是理所當然的,Maven不僅内置了依賴管理,更有一個可能擁有全世界最多Java開源軟體包的中間倉庫,Maven使用者無須進行任何配置就可以直接享用。
1.2.5 不重複發明***
【該小節内容整理自網友Arthas最早在Maven中文MSN的群内的讨論,在此表示感謝】
小張是一家小型民營軟體公司的程式員,他所在的公司要開發一個新的Web項目。經過協商,決定使用Spring、iBatis和Tapstry。jar包去哪裡找呢?公司裡估計沒有人能把Spring、iBatis和Tapstry所使用的jar包一個不少地找出來。大家的做法是,先到Spring的站點上去找一個spring.with.dependencies,然後去iBatis的網站上把所有列出來的jar包下載下傳下來,對Tapstry、Apache commons等執行同樣的操作。項目還沒有開始,WEB.INF/lib下已經有近百個jar包了,帶版本号的、不帶版本号的、有用的、沒用的、相沖突的,怎一個“亂”字了得!
在項目開發過程中,小張不時地發現版本錯誤和版本沖突問題,他隻能硬着頭皮逐一解決。項目開發到一半,經理發現最終部署的應用的體積實在太大了,要求小張去掉一些沒用的jar包,于是小張隻能加班加點地一個個删……
小張隐隐地覺得這些依賴需要一個架構或者系統來進行管理。
小張喜歡學習流行的技術,前幾年Ant十分流行,他學了,并成為了公司這方面的專家。小張知道,Ant打包,無非就是建立目錄,複制檔案,編譯源代碼,使用一堆任務,如copydir、fileset、classpath、ref、target,然後再jar、zip、war,打包就成功了。
項目經理發話了:“兄弟們,新項目來了,小張,你來寫Ant腳本!”
“是,保證完成任務!”接着,小張繼續建立一個新的XML檔案。target clean; target compile; target jar; …… 不知道他是否想過,在他寫的這麼多的Ant腳本中,有多少是重複勞動,有多少代碼會在一個又一個項目中重制。既然都差不多,有些甚至完全相同,為什麼每次都要重新編寫?
終于有一天,小張意識到了這個問題,想複用Ant腳本,于是在開會時他說:“以後就都用我這個規範的Ant腳本吧,新的項目隻要遵循我定義的目錄結構就可以了。”經理聽後覺得很有道理:“嗯,确實是個進步。”
這時新來的研究所學生發言了:“經理,用Maven吧,這個在開源社群很流行,比Ant更友善。”小張一聽很驚訝,Maven真比自己的“規範化Ant”強大?其實他不知道自己隻是在重新發明***,Maven已經有一大把現成的插件,全世界都在用,你自己不用寫任何代碼!
為什麼沒有人說“我自己寫的代碼最靈活,是以我不用Spring,我自己實作IoC;我不用Hibernate,我自己封裝JDBC”?
1.3 Maven與極限程式設計
極限程式設計(XP)是近些年在軟體行業紅得發紫的靈活開發方法,它強調擁抱變化。該軟體開發方法的創始人Kent Beck提出了XP所追求的價值、實施原則和推薦實踐。下面看一下Maven是如何适應XP的。
首先看一下Maven如何幫助XP團隊實作一些核心價值:
- 簡單。Maven暴露了一組一緻、簡潔的操作接口,能幫助團隊成員從原來的高度自定義的、複雜的建構系統中解脫出來,使用Maven現有的成熟的、穩定的元件也能簡化建構系統的複雜度。
- 交流與回報。與版本控制系統結合後,所有人都能執行最新的建構并快速得到回報。此外,自動生成的項目報告也能幫助成員了解項目的狀态,促進團隊的交流。
此外,Maven更能無縫地支援或者融入到一些主要的XP實踐中:
- 測試驅動開發(TDD)。TDD強調測試先行,所有産品都應該由測試用例覆寫。而測試是Maven生命周期的最重要的組成部分之一,并且Maven有現成的成熟插件支援業界流行的測試架構,如JUnit和TestNG。
- 十分鐘建構。十分鐘建構強調我們能夠随時快速地從源碼建構出最終的産品。這正是Maven所擅長的,隻需要一些配置,之後用一條簡單的指令就能讓Maven幫你清理、編譯、測試、打包、部署,然後得到最終的産品。
- 持續內建(CI)。CI強調項目以很短的周期(如15分鐘)內建最新的代碼。 實際上,CI的前提是源碼管理系統和建構系統。目前業界流行的CI伺服器如Hudson和CruiseControl都能很好地和Maven進行內建。也 就是說,使用Maven後,持續內建會變得更加友善。
- 富有資訊的工作區。 這條實踐強調開發者能夠快速友善地了解到項目的最新狀态。當然,Maven并不會幫你把測試覆寫率報告貼到牆上,也不會在你的工作台上放個鴨子告訴你建構 失敗了。不過使用Maven釋出的項目報告站點,并配置你需要的項目報告,如測試覆寫率報告,都能幫你把資訊推送到開發者眼前。
上述這些實踐并非隻在XP中适用。事實上,除了其他靈活開發方法如SCRUM之外,幾乎任何軟體開發方法都能借鑒這些實踐。也就是說,Maven幾乎能夠很好地支援任何軟體開發方法。
例 如,在傳統的瀑布模型開發中,項目依次要經曆需求開發、分析、設計、編碼、測試和內建釋出階段。從設計和編碼階段開始,就可以使用Maven來建立項目的 建構系統。在設計階段,也完全可以針對設計開發測試用例,然後再編寫代碼來滿足這些測試用例。然而,有了自動化建構系統,我們可以節省很多手動的測試時 間。此外,盡早地使用建構系統內建團隊的代碼,對項目也是百利而無一害。最後,Maven還能幫助我們快速地釋出項目。
第2章 Maven的安裝和配置
第1章介紹了Maven是什麼,以及為什麼要使用Maven, 我們将從本章實際開始實際接觸Maven。本章首先将介紹如何在主流的作業系統下安裝Maven,并詳細解釋Maven的安裝檔案;其次還會介紹如何在主 流的IDE中內建Maven,以及Maven安裝的最佳實踐。
2.1 在Windows上安裝Maven
2.2 在基于Unix的系統上安裝Maven
2.3 安裝目錄分析
2.4 設定HTTP代理
2.5 安裝m2eclipse
2.6 安裝NetBeans Maven插件
2.7 Maven安裝最佳實踐
2.8 小結
2.1 在Windows上安裝Maven
2.1.1 檢查JDK安裝
在安裝Maven之前,首先要确認你已經正确安裝了JDK。Maven可以運作在JDK 1.4及以上的版本上。本書的所有樣例都基于JDK 5及以上版本。打開Windows的指令行,運作如下的指令來檢查你的Java安裝:
C:\Users\Juven Xu>echo %JAVA_HOME%
C:\Users\Juven Xu>java -version
結果如圖2-1所示:
圖2-1 Windows中檢查Java安裝
上述指令首先檢查環境變量JAVA_HOME是否指向了正确的JDK目錄,接着嘗試運作java指令。如果Windows無法執行java指令,或者無法找到JAVA_HOME環境變量。你就需要檢查Java是否安裝了,或者環境變量是否設定正确。關于環境變量的設定,請參考2.1.3節。
2.1.2 下載下傳Maven
請通路Maven的下載下傳頁面:http://maven.apache.org/download.html,其中包含針對不同平台的各種版本的Maven下載下傳檔案。對于首次接觸Maven的讀者來說,推薦使用Maven 3.0,,是以下載下傳apache-maven-3.0-bin.zip。當然,如果你對Maven的源代碼感興趣并想自己建構Maven,還可以下載下傳apache-maven-3.0 -src.zip。該下載下傳頁面還提供了md5校驗和(checksum)檔案和asc數字簽名檔案,可以用來檢驗Maven分發包的正确性和安全性。
在本書編寫的時候,Maven 2的最新版本是2.2.1,Maven 3基本完全相容Maven 2,而且較之于Maven 2它性能更好,還有不少功能的改進,如果你之前一直使用Maven 2,現在正猶豫是否要更新,那就大可不必擔心了,快點嘗試下Maven 3吧!
2.1.3 本地安裝
将安裝檔案解壓到你指定的目錄中,如:
D:\bin>jar xvf "C:\Users\Juven Xu\Downloads\apache-maven-3.0--bin.zip"
這裡的Maven安裝目錄是D:\bin\apache-maven-3.0,接着需要設定環境變量,将Maven安裝配置到作業系統環境中。
打開系統屬性面闆(桌面上右鍵單擊“我的電腦”→“屬性”),點選進階系統設定,再點選環境變量,在系統變量中建立一個變量,變量名為M2_HOME,變量值為Maven的安裝目錄D:\bin\apache-maven-3.0。點選确定,接着在系統變量中找到一個名為Path的變量,在變量值的末尾加上%M2_HOME%\bin;,注意多個值之間需要有分号隔開,然後點選确定。至此,環境變量設定完成,詳細情況如圖2-2所示:
圖2-2 Windows中系統環境變量配置
這裡需要提一下的是Path環境變量,當我們在cmd中輸入指令時,Windows首先會在目前目錄中尋找可執行檔案或腳本,如果沒有找到,Windows會接着周遊環境變量Path中定義的路徑。由于我們将%M2_HOME%\bin添加到了Path中,而這裡%M2_HOME%實際上是引用了我們前面定義的另一個變量,其值是Maven的安裝目錄。是以,Windows會在執行指令時搜尋目錄D:\bin\apache-maven-3.0\bin,而mvn執行腳本的位置就是這裡。
明白了環境變量的作用,現在打開一個新的cmd視窗(這裡強調新的視窗是因為新的環境變量配置需要新的cmd視窗才能生效),運作如下指令檢查Maven的安裝情況:
C:\Users\Juven Xu>echo %M2_HOME%
C:\Users\Juven Xu>mvn -v
運作結果如圖2-3所示:
圖2-3 Windows中檢查Maven安裝
第一條指令echo %M2_HOME%用來檢查環境變量M2_HOME是否指向了正确的Maven安裝目錄;而mvn –version執行了第一條Maven指令,以檢查Windows是否能夠找到正确的mvn執行腳本。
2.1.4 更新Maven
Maven還比較年輕,更新比較頻繁,是以使用者往往會需要更新Maven安裝以獲得更多更酷的新特性,以及避免一些舊的bug。
在Windows上更新Maven非常簡便,隻需要下載下傳新的Maven安裝檔案,解壓至本地目錄,然後更新M2_HOME環境變量便可。例如,假設Maven推出了新版本3.1,我們将其下載下傳然後解壓至目錄D:\bin\apache-maven-3.1,接着遵照前一節描述的步驟編輯環境變量M2_HOME,更改其值為D:\bin\apache-maven-3.1。至此,更新就完成了。同理,如果你需要使用某一個舊版本的Maven,也隻需要編輯M2_HOME環境變量指向舊版本的安裝目錄。
2.2 在基于Unix的系統上安裝Maven
Maven是跨平台的,它可以在任何一種主流的作業系統上運作,本節将介紹如何在基于Unix的系統(包括Linux、Mac OS以及FreeBSD等)上安裝Maven。
2.2.1 下載下傳和安裝
首先,與在Windows上安裝Maven一樣,需要檢查JAVA_HOME環境變量以及Java指令,細節不再贅述,指令如下:
juven@juven-ubuntu:~$ echo $JAVA_HOME
juven@juven-ubuntu:~$ java –version
運作結果如圖2-4所示:
圖2-4 Linux中檢查Java安裝
接着到http://maven.apache.org/download.html下載下傳Maven安裝檔案,如apache-maven-3.0-bin.tar.gz,然後解壓到本地目錄:
juven@juven-ubuntu:bin$ tar -xvzf apache-maven-3.0-bin.tar.gz
現在已經建立好了一個Maven安裝目錄apache-maven-3.0,雖然直接使用該目錄配置環境變量之後就能使用Maven了,但這裡我更推薦做法是,在安裝目錄旁平行地建立一個符号連結,以友善日後的更新:
juven@juven-ubuntu:bin$ ln -s apache-maven-3.0 apache-maven
juven@juven-ubuntu:bin$ ls -l
total 4
lrwxrwxrwx 1 juven juven 18 2009-09-20 15:43 apache-maven -> apache-maven-3.0
drwxr-xr-x 6 juven juven 4096 2009-09-20 15:39 apache-maven-3.0
接下來,我們需要設定M2_HOME環境變量指向符号連結apache-maven-,并且把Maven安裝目錄下的bin/檔案夾添加到系統環境變量PATH中去:
juven@juven-ubuntu:bin$ export M2_HOME=/home/juven/bin/apache-maven
juven@juven-ubuntu:bin$ export PATH=$PATH:$M2_HOME/bin
一般來說,需要将這兩行指令加入到系統的登入shell腳本中去,以我現在的Ubuntu 8.10為例,編輯~/.bashrc檔案,添加這兩行指令。這樣,每次啟動一個終端,這些配置就能自動執行。
至此,安裝完成,我們可以運作以下指令檢查Maven安裝:
juven@juven-ubuntu:bin$ echo $M2_HOME
juven@juven-ubuntu:bin$ mvn –version
運作結果如圖2-5所示:
圖2-5 Linux中檢查Maven安裝
2.2.2 更新Maven
在基于Unix的系統上,可以利用符号連結這一工具來簡化Maven的更新,不必像在Windows上那樣,每次更新都必須更新環境變量。
前一小節中我們提到,解壓Maven安裝包到本地之後,平行地建立一個符号連結,然後在配置環境變量時引用該符号連結,這樣做是為了友善更新。現在,假設我們需要更新到新的Maven 3.1版本,同理,将安裝包解壓到與前一版本平行的目錄下,然後更新符号連結指向3.1版的目錄便可:
juven@juven-ubuntu:bin$ rm apache-maven
juven@juven-ubuntu:bin$ ln -s apache-maven-3.1/ apache-maven
juven@juven-ubuntu:bin$ ls -l
total 8
lrwxrwxrwx 1 juven juven 17 2009-09-20 16:13 apache-maven -> apache-maven-3.1 /
drwxr-xr-x 6 juven juven 4096 2009-09-20 15:39 apache-maven-3.0drwxr-xr-x 2 juven juven 4096 2009-09-20 16:09 apache-maven-3.1
同理,可以很友善地切換到Maven的任意一個版本。現在更新完成了,可以運作mvn -v進行檢查。
2.3 安裝目錄分析
本章前面的内容講述了如何在各種作業系統中安裝和更新Maven。現在我們來仔細分析一下Maven的安裝檔案。
2.3.1 M2_HOME
前面我們講到設定M2_HOME環境變量指向Maven的安裝目錄,本書之後所有使用M2_HOME的地方都指代了該安裝目錄,讓我們看一下該目錄的結構和内容:
bin
boot
conf
lib
LICENSE.txt
NOTICE.txt
README.txt
- Bin: 該目錄包含了mvn運作的腳本,這些腳本用來配置Java指令,準備好classpath和相關的Java系統屬性,然後執行Java指令。其中mvn是基于UNIX平台的shell腳本,mvn.bat是基于Windows平台的bat腳本。在指令行輸入任何一條mvn指令時,實際上就是在調用這些腳本。該目錄還包含了mvnDebug和mvnDebug.bat兩個檔案,同樣,前者是UNIX平台的shell腳本,後者是windows的bat腳本。那麼mvn和mvnDebug有什麼差別和關系呢?打開檔案我們就可以看到,兩者基本是一樣的,隻是mvnDebug多了一條MAVEN_DEBUG_OPTS配置,作用就是在運作Maven時開啟debug,以便調試Maven本身。此外,該目錄還包含m2.conf檔案,這是classworlds的配置檔案,稍微會介紹classworlds。
- Boot: 該目錄隻包含一個檔案,以maven 3.0為例,該檔案為plexus-classworlds-2.2.3.jar。plexus-classworlds是一個類加載器架構,相對于預設的java類加載器,它提供了更豐富的文法以友善配置,Maven使用該架構加載自己的類庫。更多關于classworlds的資訊請參考http://classworlds.codehaus.org/。對于一般的Maven使用者來說,不必關心該檔案。
- Conf: 該目錄包含了一個非常重要的檔案settings.xml。直接修改該檔案,就能在機器上全局地定制Maven的行為。一般情況下,我們更偏向于複制該檔案至~/.m2/目錄下(這裡~表示使用者目錄),然後修改該檔案,在使用者範圍定制Maven的行為。本書的後面将會多次提到該settings.xml,并逐漸分析其中的各個元素。
- Lib: 該目錄包含了所有Maven運作時需要的Java類庫,Maven本身是分子產品開發的,是以使用者能看到諸如mavn-core-3.0.jar、maven-model-3.0.jar之類的檔案,此外這裡還包含一些Maven用到的第三方依賴如common-cli-1.2.jar、google-collection-1.0.jar等等。(對于Maven 2來說,該目錄隻包含一個如maven-2.2.1-uber.jar的檔案原本各為獨立JAR檔案的Maven子產品和第三方類庫都被拆解後重新合并到了這個JAR檔案中)。可以說,這個lib目錄就是真正的Maven。關于該檔案,還有一點值得一提的是,使用者可以在這個目錄中找到Maven内置的超級POM,這一點在8.5小節詳細解釋。其他: LICENSE.txt記錄了Maven使用的軟體許可證Apache License Version 2.0;NOTICE.txt記錄了Maven包含的第三方軟體;而README.txt則包含了Maven的簡要介紹,包括安裝需求及如何安裝的簡要指令等等。
2.3.2 ~/.m2
在講述該小節之前,我們先運作一條簡單的指令:mvn help:system。該指令會列印出所有的Java系統屬性和環境變量,這些資訊對我們日常的程式設計工作很有幫助。這裡暫不解釋help:system涉及的文法,運作這條指令的目的是為了讓Maven執行一個真正的任務。我們可以從指令行輸出看到Maven會下載下傳maven-help-plugin,包括pom檔案和jar檔案。這些檔案都被下載下傳到了Maven本地倉庫中。
現在打開使用者目錄,比如目前的使用者目錄是C:\Users\Juven Xu\,你可以在Vista和Windows7中找到類似的使用者目錄。如果是更早版本的Windows,該目錄應該類似于C:\Document and Settings\Juven Xu\。在基于Unix的系統上,直接輸入cd 回車,就可以轉到使用者目錄。為了友善,本書統一使用符号 ~ 指代使用者目錄。
在使用者目錄下,我們可以發現.m2檔案夾。預設情況下,該檔案夾下放置了Maven本地倉庫.m2/repository。所有的Maven構件(artifact)都被存儲到該倉庫中,以友善重用。我們可以到~/.m2/repository/org/apache/maven/plugins/maven-help-plugins/目錄下找到剛才下載下傳的maven-help-plugin的pom檔案和jar檔案。Maven根據一套規則來确定任何一個構件在倉庫中的位置,這一點本書第6章将會詳細闡述。由于Maven倉庫是通過簡單檔案系統透明地展示給Maven使用者的,有些時候可以繞過Maven直接檢視或修改倉庫檔案,在遇到疑難問題時,這往往十分有用。
預設情況下,~/.m2目錄下除了repository倉庫之外就沒有其他目錄和檔案了,不過大多數Maven使用者需要複制M2_HOME/conf/settings.xml檔案到~/.m2/settings.xml。這是一條最佳實踐,我們将在本章最後一小節詳細解釋。
2.4 設定HTTP代理
有時候你所在的公司由于安全因素考慮,要求你使用通過安全認證的代理通路網際網路。這種情況下,就需要為Maven配置HTTP代理,才能讓它正常通路外部倉庫,以下載下傳所需要的資源。
首先确認自己無法直接通路公共的Maven中間倉庫,直接運作指令ping repo1.maven.org可以檢查網絡。如果真的需要代理,先檢查一下代理伺服器是否暢通,比如現在有一個IP位址為218.14.227.197,端口為3128的代理服務,我們可以運作telnet 218.14.227.197 3128來檢測該位址的該端口是否暢通。如果得到出錯資訊,需要先擷取正确的代理服務資訊;如果telnet連接配接正确,則輸入ctrl+],然後q,回車,退出即可。
檢查完畢之後,編輯~/.m2/settings.xml檔案(如果沒有該檔案,則複制$M2_HOME/conf/settings.xml)。添加代理配置如下:
<settings>
…
<proxies>
<proxy>
<id>my-proxy</id>
<active>true</active>
<protocol>http</protocol>
<host>218.14.227.197</host>
<port>3128</port>
<!--
<username>***</username>
<password>***</password>
<nonProxyHosts>repository.mycom.com|*.google.com</nonProxyHosts>
-->
</proxy>
</proxies>
…
</settings>
這段配置十分簡單,proxies下可以有多個proxy元素,如果你聲明了多個proxy元素,則預設情況下第一個被激活的proxy會生效。這裡聲明了一個id為my-proxy的代理,active的值為true表示激活該代理,protocol表示使用的代理協定,這裡是http。當然,最重要的是指定正确的主機名(host元素)和端口(port元素)。上述XML配置中我注釋掉了username、password、nonProxyHost幾個元素,當你的代理服務需要認證時,就需要配置username和password。nonProxyHost元素用來指定哪些主機名不需要代理,可以使用 | 符号來分隔多個主機名。此外,該配置也支援通配符,如*.google.com表示所有以google.com結尾的域名通路都不要通過代理。
2.5 安裝m2eclipse
Eclipse是一款非常優秀的IDE。除了基本的文法标亮、代碼補齊、XML編輯等基本功能外,最新版的Eclipse還能很好地支援重構,并且內建了JUnit、CVS、Mylyn等各種流行工具。可惜Eclipse預設沒有內建對Maven的支援。幸運的是,由Maven之父Jason Van Zyl創立的Sonatype公司建立了m2eclipse項目,這是Eclipse下的一款十分強大的Maven插件,可以通路http://m2eclipse.sonatype.org/ 了解更多該項目的資訊。
本小節将先介紹如何安裝m2eclipse插件,本書後續的章節會逐漸介紹m2eclipse插件的使用。
現在我以Eclipse 3.6為例逐漸講解m2eclipse的安裝。啟動Eclipse之後,在菜單欄中選擇Help,然後選擇Install New Software…,接着你會看到一個Install對話框,點選Work with:字段邊上的Add按鈕,你會得到一個新的Add Repository對話框,在Name字段中輸入m2e,Location字段中輸入http://m2eclipse.sonatype.org/sites/m2e,然後點選OK。Eclipse會下載下傳m2eclipse安裝站點上的資源資訊。等待資源載入完成之後,我們再将其全部展開,就能看到圖2-6所示的界面:
圖2-6 m2eclipse的核心安裝資源清單
如圖顯示了m2eclipse的核心子產品Maven Integration for Eclipse (Required),選擇後點選Next >,Eclipse會自動計算子產品間依賴,然後給出一個将被安裝的子產品清單,确認無誤後,繼續點選Next >,這時我們會看到許可證資訊,m2eclipse使用的開源許可證是Eclipse Public License v1.0,選擇I accept the terms of the license agreements,然後點選Finish,接着就耐心等待Eclipse下載下傳安裝這些子產品,如圖2-7所示:
圖2-7:m2eclipse安裝進度
除了核心元件之外,m2eclipse還提供了一組額外元件,主要是為了友善與其它工具如Subversion進行內建,這些元件的安裝位址為http://m2eclipse.sonatype.org/sites/m2e-extras。使用前面類似的安裝方法,我們可以看到如圖2-8的元件清單:
圖2-8:m2eclipse的額外元件安裝資源清單
下面簡單解釋一下這些元件的用途:
- 1. 重要的
- 2. 不重要的
- Maven SCM handler for Subclipse (Optional):Subversion是非常流行的版本管理工具,該子產品能夠幫助我們直接從Subversion伺服器簽出Maven項目,不過前提是需要首先安裝Subclipse(http://subclipse.tigris.org/)。
- Maven SCM Integration (Optional):Eclipse環境中Maven與SCM內建核心的子產品,它利用各種SCM工具如SVN實作Maven項目的簽出和具體化等操作。
- Maven issue tracking configurator for Mylyn 3.x (Optional):該子產品能夠幫助我們使用POM中的缺陷跟蹤系統資訊連接配接Mylyn至伺服器。
- Maven SCM handler for Team/CVS (Optional):該子產品幫助我們從CVS伺服器簽出Maven項目,如果你還在使用CVS,就需要安裝它。
- Maven Integration for WTP (Optional):使用該子產品可以讓Eclipse自動讀取POM資訊并配置WTP項目。、
- M2eclipse Extensions Development Support (Optional):用來支援擴充m2eclipse,一般使用者不會用到。
- Project configurators for commonly used maven plugins (temporary):一個臨時的元件,用來支援一些Maven插件與Eclipse的內建,建議安裝。
讀者可以根據自己的需要安裝相應元件,具體步驟不再贅述。
待安裝完畢後,重新開機Eclipse,現在讓我們驗證一下m2eclipse是否正确安裝了。首先,點選菜單欄中的Help,然後選擇About Eclipse,在彈出的對話框中,點選Installation Details按鈕,會得到一個對話框,在Installed Software标簽欄中,檢查剛才我們選擇的子產品是否在這個清單中,如圖2-9所示:
圖2-9m2eclipse安裝結果
如果一切沒問題,我們再檢查一下Eclipse現在是否已經支援建立Maven項目,依次點選菜單欄中的File→New→Other,在彈出的對話框中,找到Maven一項,再将其展開,你應該能夠看到如圖2-10所示的對話框:
圖2-10 Eclipse中建立Maven項目向導
如果一切正常,說明m2eclipse已經正确安裝了。
最後,關于m2eclipse的安裝,需要提醒的一點是,你可能會在使用m2eclipse時遇到類似這樣的錯誤:
09-10-6 上午01時14分49秒: Eclipse is running in a JRE, but a JDK is required
Some Maven plugins may not work when importing projects or updating source folders.
這是因為Eclipse預設是運作在JRE上的,而m2eclipse的一些功能要求使用JDK,解決方法是配置Eclipse安裝目錄的eclipse.ini檔案,添加vm配置指向JDK,如:
--launcher.XXMaxPermSize
256m
-vm
D:\java\jdk1.6.0_07\bin\javaw.exe
-vmargs
-Dosgi.requiredJavaVersion=1.5
-Xms128m
-Xmx256m
2.6 安裝NetBeans Maven插件
本小節會先介紹如何在NetBeans上安裝Maven插件,後面的章節中還會介紹NetBeans中具體的Maven操作。
首先,如果你正在使用NetBeans 6.7及以上版本,那麼Maven插件已經預裝了。你可以檢查Maven插件安裝,點選菜單欄中的工具,接着選擇插件,在彈出的插件對話框中選擇已安裝标簽,你應該能夠看到Maven插件,如圖2-11所示:
圖2-11 已安裝的NetBeans Maven插件
如果你在使用NetBeans 6.7之前的版本,或者由于某些原因NetBeans Maven插件被解除安裝了,那麼你就需要安裝NetBeans Maven插件,下面我們以NetBeans 6.1為例,介紹Maven插件的安裝。
同樣,點選菜單欄中的工具,選擇插件,在彈出的插件對話框中選擇可用插件标簽,接着在右邊的搜尋框内輸入Maven,這時你會在左邊的清單中看到一個名為Maven的插件,選擇該插件,然後點選下面的安裝按鈕,如圖2-12所示:
圖2-12 安裝NetBeans Maven插件
接着在随後的對話框中根據提示操作,閱讀相關許可證并接受,NetBeans會自動幫我們下載下傳并安裝Maven插件,結束之後會提示安裝完成,之後再點選插件對話框的已安裝标簽,就能看到已經激活的Maven插件。
最後,為了确認Maven插件确實已經正确安裝了,可以看一下NetBeans是否已經擁有建立Maven項目的相關菜單。在菜單欄中選擇檔案,然後選擇建立項目,這時應該能夠看到項目類别中有Maven一項,選擇該類别,右邊會相應地顯示Maven項目和基于現有POM的Maven項目,如圖2-13所示:
圖2-13 NetBeans中建立Maven項目向導
如果你能看到類似的對話框,說明NetBeans Maven已經正确安裝了。
2.7 Maven安裝最佳實踐
本節介紹一些在安裝Maven過程中不是必須的,但十分有用的實踐。
2.7.1 設定MAVEN_OPTS環境變量
本章前面介紹Maven安裝目錄時我們了解到,運作mvn指令實際上是執行了Java指令,既然是運作Java,那麼運作Java指令可用的參數當然也應該在運作mvn指令時可用。這個時候,MAVEN_OPTS環境變量就能派上用場。
我們通常需要設定MAVEN_OPTS的值為:-Xms128m -Xmx512m,因為Java預設的最大可用記憶體往往不能夠滿足Maven運作的需要,比如在項目較大時,使用Maven生成項目站點需要占用大量的記憶體,如果沒有該配置,我們很容易得到java.lang.OutOfMemeoryError。是以,一開始就配置該變量是推薦的做法。
關于如何設定環境變量,請參考前面設定M2_HOME環境變量的做法,盡量不要直接修改mvn.bat或者mvn這兩個Maven執行腳本檔案。因為如果修改了腳本檔案,更新Maven時你就不得不再次修改,一來麻煩,二來容易忘記。同理,我們應該盡可能地不去修改任何Maven安裝目錄下的檔案。
2.7.2 配置使用者範圍settings.xml
Maven使用者可以選擇配置$M2_HOME/conf/settings.xml或者~/.m2/settings.xml。前者是全局範圍的,整台機器上的所有使用者都會直接受到該配置的影響,而後者是使用者範圍的,隻有目前使用者才會受到該配置的影響。
我們推薦使用使用者範圍的settings.xml,主要原因是為了避免無意識地影響到系統中的其他使用者。當然,如果你有切實的需求,需要統一系統中所有使用者的settings.xml配置,當然應該使用全局範圍的settings.xml。
除了影響範圍這一因素,配置使用者範圍settings.xml檔案還便于Maven更新。直接修改conf目錄下的settings.xml會導緻Maven更新不便,每次更新到新版本的Maven,都需要複制settings.xml檔案,如果使用~/.m2目錄下的settings.xml,就不會影響到Maven安裝檔案,更新時就不需要觸動settings.xml檔案。
2.7.3 不要使用IDE内嵌的Maven
無論是Eclipse還是NetBeans,當我們內建Maven時,都會安裝上一個内嵌的Maven,這個内嵌的Maven通常會比較新,但不一定很穩定,而且往往也會和我們在指令行使用的Maven不是同一個版本。這裡有會出現兩個潛在的問題:首先,較新版本的Maven存在很多不穩定因素,容易造成一些難以了解的問題;其次,除了IDE,我們也經常還會使用指令行的Maven,如果版本不一緻,容易造成建構行為的不一緻,這是我們所不希望看到的。是以,我們應該在IDE中配置Maven插件時使用與指令行一緻的Maven。
在m2eclipse環境中,點選菜單欄中的Windows,然後選擇Preferences,在彈出的對話框中,展開左邊的Maven項,選擇Installation子項,在右邊的面闆中,我們能夠看到有一個預設的Embedded Maven安裝被選中了,點選Add…然後選擇我們的Maven安裝目錄M2_HOME,添加完畢之後選擇這一個外部的Maven,如圖2-14所示:
圖2-14 在Eclipse中使用外部Maven
NetBeans Maven插件預設會偵測PATH環境變量,是以會直接使用與指令行一緻的Maven環境。依次點選菜單欄中的工具→選項→其他→Maven标簽欄,你就能看到如圖2-15所示的配置:
圖2-15 在NetBeans中使用外部Maven
2.8 小結
本章詳細介紹了在各種作業系統平台上安裝Maven,并對Maven安裝目錄進行了深入的分析,在指令行的基礎上,本章又進一步介紹了Maven與主流IDE Eclipse及NetBeans的內建,本章最後還介紹了一些與Maven安裝相關的最佳實踐。本書下一章會建立一個Hello World項目,帶領讀者配置和建構Maven項目。
第3章 Maven使用入門
到目前為止,我們已經大概了解并安裝好了Maven,現在,我們開始 建立一個最簡單的Hello World項目。如果你是初次接觸Maven,我建議你按照本章的内容一步步地編寫代碼并執行,可能你會碰到一些概念暫時難以了解,不用着急,記下這些疑 難點,相信本書的後續章節會幫你逐一解答。
3.1 編寫POM
3.2 編寫主代碼
3.3 編寫測試代碼
3.4 打包和運作
3.5 使用Archetype生成項目骨架
3.6 m2eclipse簡單使用
3.7 NetBeans Maven插件簡單使用
3.8 小結
3.1 編寫POM
就像Make的Makefile,Ant的build.xml一樣,Maven項目的核心是pom.xml。POM(Project Object Model,項目對象模型)定義了項目的基本資訊,用于描述項目如何建構,聲明項目依賴,等等。現在我們先為Hello World項目編寫一個最簡單的pom.xml。
首先建立一個名為hello-world的檔案夾(本書中各章的代碼都會對應一個以ch開頭的項目),打開該檔案夾,建立一個名為pom.xml的檔案,輸入其内容如代碼清單3-1:
代碼清單3-1:Hello World的POM
- <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.juvenxu.mvnbook</groupId>
- <artifactId>hello-world</artifactId>
- <version>1.0-SNAPSHOT</version>
- <name>Maven Hello World Project</name>
- </project>
- </span>
代碼的第一行是XML頭,指定了該xml文檔的版本和編碼方式。緊接着是project元素,project是所有pom.xml的根元素,它還聲明了一些POM相關的命名空間及xsd元素,雖然這些屬性不是必須的,但使用這些屬性能夠讓第三方工具(如IDE中的XML編輯器)幫助我們快速編輯POM。
根元素下的第一個子元素modelVersion指定了目前POM模型的版本,對于Maven2及Maven 3來說,它隻能是4.0.0。
這段代碼中最重要的是groupId,artifactId和version三行。這三個元素定義了一個項目基本的坐标,在Maven的世界,任何的jar、pom或者war都是以基于這些基本的坐标進行區分的。
groupId定義了項目屬于哪個組,這個組往往和項目所在的組織或公司存在關聯,譬如你在googlecode上建立了一個名為myapp的項目,那麼groupId就應該是com.googlecode.myapp,如果你的公司是mycom,有一個項目為myapp,那麼groupId就應該是com.mycom.myapp。本書中所有的代碼都基于groupId com.juvenxu.mvnbook。
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.1、2.0等等。本書的6.5小節會詳細介紹SNAPSHOT,第13章介紹如何使用Maven管理項目版本的更新釋出。
最後一個name元素聲明了一個對于使用者更為友好的項目名稱,雖然這不是必須的,但我還是推薦為每個POM聲明name,以友善資訊交流。
沒有任何實際的Java代碼,我們就能夠定義一個Maven項目的POM,這展現了Maven的一大優點,它能讓項目對象模型最大程度地與實際代碼相獨立,我們可以稱之為解耦,或者正交性,這在很大程度上避免了Java代碼和POM代碼的互相影響。比如當項目需要更新版本時,隻需要修改POM,而不需要更改Java代碼;而在POM穩定之後,日常的Java代碼開發工作基本不涉及POM的修改。
3.2 編寫主代碼
項目主代碼和測試代碼不同,項目的主代碼會被打包到最終的構件中(比如jar),而測試代碼隻在運作測試時用到,不會被打包。預設情況下,Maven假設項目主代碼位于src/main/java目錄,我們遵循Maven的約定,建立該目錄,然後在該目錄下建立檔案com/juvenxu/mvnbook/helloworld/HelloWorld.java,其内容如代碼清單3-2:
代碼清單3-2:Hello World的主代碼
- <span style="font-size: small;">package com.juvenxu.mvnbook.helloworld;
- public class HelloWorld
- {
- public String sayHello()
- {
- return "Hello Maven";
- }
- public static void main(String[] args)
- {
- System.out.print( new HelloWorld().sayHello() );
- }
- }
- </span>
這是一個簡單的Java類,它有一個sayHello()方法,傳回一個String。同時這個類還帶有一個main方法,建立一個HelloWorld執行個體,調用sayHello()方法,并将結果輸出到控制台。
關于該Java代碼有兩點需要注意。首先,在95%以上的情況下,我們應該把項目主代碼放到src/main/java/目錄下(遵循Maven的約定),而無須額外的配置,Maven會自動搜尋該目錄找到項目主代碼。其次,該Java類的包名是com.juvenxu.mvnbook.helloworld,這與我們之前在POM中定義的groupId和artifactId相吻合。一般來說,項目中Java類的包都應該基于項目的groupId和artifactId,這樣更加清晰,更加符合邏輯,也友善搜尋構件或者Java類。
代碼編寫完畢後,我們使用Maven進行編譯,在項目根目錄下運作指令 mvn clean compile ,我們會得到如下輸出:
- <span style="font-size: small;">[INFO] Scanning for projects...
- [INFO] ------------------------------------------------------------------------
- [INFO] Building Maven Hello World Project
- [INFO] task-segment: [clean, compile]
- [INFO] ------------------------------------------------------------------------
- [INFO] [clean:clean {execution: default-clean}]
- [INFO] Deleting directory D:\code\hello-world\target
- [INFO] [resources:resources {execution: default-resources}]
- [INFO] skip non existing resourceDirectory D: \code\hello-world\src\main\resources
- [INFO] [compiler:compile {execution: default-compile}]
- [INFO] Compiling 1 source file to D: \code\hello-world\target\classes
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- [INFO] ------------------------------------------------------------------------
- [INFO] Total time: 1 second
- [INFO] Finished at: Fri Oct 09 02:08:09 CST 2009
- [INFO] Final Memory: 9M/16M
- [INFO] ------------------------------------------------------------------------
- </span>
clean告訴Maven清理輸出目錄target/,compile告訴Maven編譯項目主代碼,從輸出中我們看到Maven首先執行了clean:clean任務,删除target/目錄,預設情況下Maven建構的所有輸出都在target/目錄中;接着執行resources:resources任務(未定義項目資源,暫且略過);最後執行compiler:compile任務,将項目主代碼編譯至target/classes目錄(編譯好的類為com/juvenxu/mvnbook/helloworld/HelloWorld.Class)。
上文提到的clean:clean、resources:resources,以及compiler:compile對應了一些Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标,後文會詳細講述Maven插件及其編寫方法。
至此,Maven在沒有任何額外的配置的情況下就執行了項目的清理和編譯任務,接下來,我們編寫一些單元測試代碼并讓Maven執行自動化測試。
3.3 編寫測試代碼
為了使項目結構保持清晰,主代碼與測試代碼應該分别位于獨立的目錄中。3.2節講過Maven項目中預設的主代碼目錄是src/main/java,對應地,Maven項目中預設的測試代碼目錄是src/test/java。是以,在編寫測試用例之前,我們先建立該目錄。
在Java世界中,由Kent Beck和Erich Gamma建立的JUnit是事實上的單元測試标準。要使用JUnit,我們首先需要為Hello World項目添加一個JUnit依賴,修改項目的POM如代碼清單3-3:
代碼清單3-3:為Hello World的POM添加依賴
- <?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.juvenxu.mvnbook</groupId>
- <artifactId>hello-world</artifactId>
- <version>1.0-SNAPSHOT</version>
- <name>Maven Hello World Project</name>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.7</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- </project>
代碼中添加了dependencies元素,該元素下可以包含多個dependency元素以聲明項目的依賴,這裡我們添加了一個依賴——groupId是junit,artifactId是junit,version是4.7。前面我們提到groupId、artifactId和version是任何一個Maven項目最基本的坐标,JUnit也不例外,有了這段聲明,Maven就能夠自動下載下傳junit-4.7.jar。也許你會問,Maven從哪裡下載下傳這個jar呢?在Maven之前,我們可以去JUnit的官網下載下傳分發包。而現在有了Maven,它會自動通路中間倉庫(http://repo1.maven.org/maven2/),下載下傳需要的檔案。讀者也可以自己通路該倉庫,打開路徑junit/junit/4.7/,就能看到junit-4.7.pom和junit-4.7.jar。本書第6章會詳細介紹Maven倉庫及中間倉庫。
上述POM代碼中還有一個值為test的元素scope,scope為依賴範圍,若依賴範圍為test則表示該依賴隻對測試有效,換句話說,測試代碼中的import JUnit代碼是沒有問題的,但是如果我們在主代碼中用import JUnit代碼,就會造成編譯錯誤。如果不聲明依賴範圍,那麼預設值就是compile,表示該依賴對主代碼和測試代碼都有效。
配置了測試依賴,接着就可以編寫測試類,回顧一下前面的HelloWorld類,現在我們要測試該類的sayHello()方法,檢查其傳回值是否為“Hello Maven”。在src/test/java目錄下建立檔案,其内容如代碼清單3-4:
代碼清單3-4:Hello World的測試代碼
- package com.juvenxu.mvnbook.helloworld;
- import static org.junit.Assert.assertEquals;
- import org.junit.Test;
- public class HelloWorldTest
- {
- @Test
- public void testSayHello()
- {
- HelloWorld helloWorld = new HelloWorld();
- String result = helloWorld.sayHello();
- assertEquals( "Hello Maven", result );
- }
- }
一個典型的單元測試包含三個步驟:一,準備測試類及資料;二,執行要測試的行為;三,檢查結果。上述樣例中,我們首先初始化了一個要測試的HelloWorld執行個體,接着執行該執行個體的sayHello()方法并儲存結果到result變量中,最後使用JUnit架構的Assert類檢查結果是否為我們期望的”Hello Maven”。在JUnit 3中,約定所有需要執行測試的方法都以test開頭,這裡我們使用了JUnit 4,但我們仍然遵循這一約定,在JUnit 4中,需要執行的測試方法都應該以@Test進行标注。
測試用例編寫完畢之後就可以調用Maven執行測試,運作 mvn clean test :
- [INFO] Scanning for projects...
- [INFO] ------------------------------------------------------------------------
- [INFO] Building Maven Hello World Project
- [INFO] task-segment: [clean, test]
- [INFO] ------------------------------------------------------------------------
- [INFO] [clean:clean {execution: default-clean}]
- [INFO] Deleting directory D:\git-juven\mvnbook\code\hello-world\target
- [INFO] [resources:resources {execution: default-resources}]
- …
- Downloading: http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.pom
- 1K downloaded (junit-4.7.pom)
- [INFO] [compiler:compile {execution: default-compile}]
- [INFO] Compiling 1 source file to D: \code\hello-world\target\classes
- [INFO] [resources:testResources {execution: default-testResources}]
- …
- Downloading: http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.jar
- 226K downloaded (junit-4.7.jar)
- [INFO] [compiler:testCompile {execution: default-testCompile}]
- [INFO] Compiling 1 source file to D:\ code\hello-world\target\test-classes
- [INFO] ------------------------------------------------------------------------
- [ERROR] BUILD FAILURE
- [INFO] ------------------------------------------------------------------------
- [INFO] Compilation failure
- D:\code\hello-world\src\test\java\com\juvenxu\mvnbook\helloworld\HelloWorldTest.java:[8,5] -source 1.3 中不支援注釋
- (請使用 -source 5 或更高版本以啟用注釋)
- @Test
- [INFO] ------------------------------------------------------------------------
- [INFO] For more information, run Maven with the -e switch
- …
不幸的是建構失敗了,不過我們先耐心分析一下這段輸出(為了本書的簡潔,一些不重要的資訊我用省略号略去了)。指令行輸入的是mvn clean test,而Maven實際執行的可不止這兩個任務,還有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。暫時我們需要了解的是,在Maven執行測試(test)之前,它會先自動執行項目主資源處理,主代碼編譯,測試資源處理,測試代碼編譯等工作,這是Maven生命周期的一個特性,本書後續章節會詳細解釋Maven的生命周期。
從輸出中我們還看到:Maven從中間倉庫下載下傳了junit-4.7.pom和junit-4.7.jar這兩個檔案到本地倉庫(~/.m2/repository)中,供所有Maven項目使用。
建構在執行compiler:testCompile任務的時候失敗了,Maven輸出提示我們需要使用-source 5或更高版本以啟動注釋,也就是前面提到的JUnit 4的@Test注解。這是Maven初學者常常會遇到的一個問題。由于曆史原因,Maven的核心插件之一compiler插件預設隻支援編譯Java 1.3,是以我們需要配置該插件使其支援Java 5,見代碼清單3-5:
代碼清單3-5:配置maven-compiler-plugin支援Java 5
- <project>
- …
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- </configuration>
- </plugin>
- </plugins>
- </build>
- …
- </project>
該POM省略了除插件配置以外的其他部分,我們暫且不去關心插件配置的細節,隻需要知道compiler插件支援Java 5的編譯。現在再執行mvn clean test,輸出如下:
- …
- [INFO] [compiler:testCompile {execution: default-testCompile}]
- [INFO] Compiling 1 source file to D: \code\hello-world\target\test-classes
- [INFO] [surefire:test {execution: default-test}]
- [INFO] Surefire report directory: D:\code\hello-world\target\surefire-reports
- -------------------------------------------------------
- T E S T S
- -------------------------------------------------------
- Running com.juvenxu.mvnbook.helloworld.HelloWorldTest
- Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.055 sec
- Results :
- Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
- [INFO] ------------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- [INFO] ------------------------------------------------------------------------
- …
我們看到compiler:testCompile任務執行成功了,測試代碼通過編譯之後在target/test-classes下生成了二進制檔案,緊接着surefire:test任務運作測試,surefire是Maven世界中負責執行測試的插件,這裡它運作測試用例HelloWorldTest,并且輸出測試報告,顯示一共運作了多少測試,失敗了多少,出錯了多少,跳過了多少。顯然,我們的測試通過了——BUILD SUCCESSFUL。
3.4 打包和運作
将項目進行編譯、測試之後,下一個重要步驟就是打包(package)。Hello World的POM中沒有指定打包類型,使用預設打包類型jar,我們可以簡單地執行指令 mvn clean package 進行打包,可以看到如下輸出:
- …
- Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
- [INFO] [jar:jar {execution: default-jar}]
- [INFO] Building jar: D:\code\hello-world\target\hello-world-1.0-SNAPSHOT.jar
- [INFO]
- --------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- …
類似地,Maven會在打包之前執行編譯、測試等操作。這裡我們看到jar:jar任務負責打包,實際上就是jar插件的jar目标将項目主代碼打包成一個名為hello-world-1.0-SNAPSHOT.jar的檔案,該檔案也位于target/輸出目錄中,它是根據artifact-version.jar規則進行命名的,如有需要,我們還可以使用finalName來自定義該檔案的名稱,這裡暫且不展開,本書後面會詳細解釋。
至此,我們得到了項目的輸出,如果有需要的話,就可以複制這個jar檔案到其他項目的Classpath中進而使用HelloWorld類。但是,如何才能讓其他的Maven項目直接引用這個jar呢?我們還需要一個安裝的步驟,執行 mvn clean install:
- …
- [INFO] [jar:jar {execution: default-jar}]
- [INFO] Building jar: D: \code\hello-world\target\hello-world-1.0-SNAPSHOT.jar
- [INFO] [install:install {execution: default-install}]
- [INFO] Installing D:\code\hello-world\target\hello-world-1.0-SNAPSHOT.jar to C:\Users\juven\.m2\repository\com\juvenxu\mvnbook\hello-world\1.0-SNAPSHOT\hello-world-1.0-SNAPSHOT.jar
- [INFO]
- ------------------------------------------------------------------------
- [INFO] BUILD SUCCESSFUL
- …
在打包之後,我們又執行了安裝任務install:install,從輸出我們看到該任務将項目輸出的jar安裝到了Maven本地倉庫中,我們可以打開相應的檔案夾看到Hello World項目的pom和jar。之前講述JUnit的POM及jar的下載下傳的時候,我們說隻有構件被下載下傳到本地倉庫後,才能由所有Maven項目使用,這裡是同樣的道理,隻有将Hello World的構件安裝到本地倉庫之後,其他Maven項目才能使用它。
我們已經将體驗了Maven最主要的指令:mvn clean compile、mvn clean test、mvn clean package、mvn clean install。執行test之前是會先執行compile的,執行package之前是會先執行test的,而類似地,install之前會執行package。我們可以在任何一個Maven項目中執行這些指令,而且我們已經清楚它們是用來做什麼的。
到目前為止,我們還沒有運作Hello World項目,不要忘了HelloWorld類可是有一個main方法的。預設打包生成的jar是不能夠直接運作的,因為帶有main方法的類資訊不會添加到manifest中(我們可以打開jar檔案中的META-INF/MANIFEST.MF檔案,将無法看到Main-Class一行)。為了生成可執行的jar檔案,我們需要借助maven-shade-plugin,配置該插件如下:
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-shade-plugin</artifactId>
- <version>1.2.1</version>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>shade</goal>
- </goals>
- <configuration>
- <transformers>
- <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.juvenxu.mvnbook.helloworld.HelloWorld</mainClass>
- </transformer>
- </transformers>
- </configuration>
- </execution>
- </executions>
- </plugin>
plugin元素在POM中的相對位置應該在<project><build><plugins>下面。我們配置了mainClass為com.juvenxu.mvnbook.helloworld.HelloWorld,項目在打包時會将該資訊放到MANIFEST中。現在執行 mvn clean install ,待建構完成之後打開target/目錄,我們可以看到hello-world-1.0-SNAPSHOT.jar和original-hello-world-1.0-SNAPSHOT.jar,前者是帶有Main-Class資訊的可運作jar,後者是原始的jar,打開hello-world-1.0-SNAPSHOT.jar的META-INF/MANIFEST.MF,可以看到它包含這樣一行資訊:
Main-Class: com.juvenxu.mvnbook.helloworld.HelloWorld
現在,我們在項目根目錄中執行該jar檔案:
D: \code\hello-world>java -jar target\hello-world-1.0-SNAPSHOT.jar
Hello Maven
控制台輸出為Hello Maven,這正是我們所期望的。
本小節介紹了Hello World項目,側重點是Maven而非Java代碼本身,介紹了POM、Maven項目結構、以及如何編譯、測試、打包,等等。
3.5 使用Archetype生成項目骨架
Hello World項目中有一些Maven的約定:在項目的根目錄中放置pom.xml,在src/main/java目錄中放置項目的主代碼,在src/test/java中放置項目的測試代碼。我之是以一步一步地展示這些步驟,是為了能讓可能是Maven初學者的你得到最實際的感受。我們稱這些基本的目錄結構和pom.xml檔案内容稱為項目的骨架,當你第一次建立項目骨架的時候,你還會饒有興趣地去體會這些預設約定背後的思想,第二次,第三次,你也許還會滿意自己的熟練程度,但第四、第五次做同樣的事情,就會讓程式員惱火了,為此Maven提供了Archetype以幫助我們快速勾勒出項目骨架。
還是以Hello World為例,我們使用maven archetype來建立該項目的骨架,離開目前的Maven項目目錄。
如果是Maven 3,簡單的運作:
mvn archetype:generate
如果是Maven 2,最好運作如下指令:
mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-5:generate
很多資料會讓你直接使用更為簡單的 mvn archetype:generate 指令,但在Maven2中這是不安全的,因為該指令沒有指定archetype插件的版本,于是Maven會自動去下載下傳最新的版本,進而可能得到不穩定的SNAPSHOT版本,導緻運作失敗。然而在Maven 3中,即使使用者沒有指定版本,Maven也隻會解析最新的穩定版本,是以這是安全的,具體内容見7.7小節。
我們實際上是在運作插件maven-archetype-plugin,注意冒号的分隔,其格式為 groupId:artifactId:version:goal,org.apache.maven.plugins 是maven官方插件的groupId,maven-archetype-plugin 是archetype插件的artifactId,2.0-alpha-5 是目前該插件最新的穩定版,generate是我們要使用的插件目标。
緊接着我們會看到一段長長的輸出,有很多可用的archetype供我們選擇,包括著名的Appfuse項目的archetype,JPA項目的archetype等等。每一個archetype前面都會對應有一個編号,同時指令行會提示一個預設的編号,其對應的archetype為maven-archetype-quickstart,我們直接回車以選擇該archetype,緊接着Maven會提示我們輸入要建立項目的groupId、artifactId、 version、以及包名package,如下輸入并确認:
- Define value for groupId: : com.juvenxu.mvnbook
- Define value for artifactId: : hello-world
- Define value for version: 1.0-SNAPSHOT: :
- Define value for package: com.juvenxu.mvnbook: : com.juvenxu.mvnbook.helloworld
- Confirm properties configuration:
- groupId: com.juvenxu.mvnbook
- artifactId: hello-world
- version: 1.0-SNAPSHOT
- package: com.juvenxu.mvnbook.helloworld
- Y: : Y
Archetype插件将根據我們提供的資訊建立項目骨架。在目前目錄下,Archetype插件會建立一個名為hello-world(我們定義的artifactId)的子目錄,從中可以看到項目的基本結構:基本的pom.xml已經被建立,裡面包含了必要的資訊以及一個junit依賴;主代碼目錄src/main/java已經被建立,在該目錄下還有一個Java類com.juvenxu.mvnbook.helloworld.App,注意這裡使用到了我們剛才定義的包名,而這個類也僅僅隻有一個簡單的輸出Hello World!的main方法;測試代碼目錄src/test/java也被建立好了,并且包含了一個測試用例com.juvenxu.mvnbook.helloworld.AppTest。
Archetype可以幫助我們迅速地建構起項目的骨架,在前面的例子中,我們完全可以在Archetype生成的骨架的基礎上開發Hello World項目以節省我們大量時間。
此外,我們這裡僅僅是看到了一個最簡單的archetype,如果你有很多項目擁有類似的自定義項目結構以及配置檔案,你完全可以一勞永逸地開發自己的archetype,然後在這些項目中使用自定義的archetype來快速生成項目骨架,本書後面的章節會詳細闡述如何開發Maven Archetype。
3.6 m2eclipse簡單使用
介紹前面Hello World項目的時候,我們并沒有涉及IDE,如此簡單的一個項目,使用最簡單的編輯器也能很快完成,但對于稍微大一些的項目來說,沒有IDE就是不可想象的,本節我們先介紹m2eclipse的基本使用。
3.6.1 導入Maven項目
第2章介紹了如何安裝m2eclipse,現在,我們使用m2ecilpse導入Hello World項目。選擇菜單項File,然後選擇Import,我們會看到一個Import對話框,在該對話框中選擇General目錄下的Maven Projects,然後點選Next,就會出現Import Projects對話框,在該對話框中點選Browse…選擇Hello World的根目錄(即包含pom.xml檔案的那個目錄),這時對話框中的Projects:部分就會顯示該目錄包含的Maven項目,如圖3-1所示:
圖3-1 在Eclipse中導入Maven項目
點選Finish之後,m2ecilpse就會将該項目導入到目前的workspace中,導入完成之後,我們就可以在Package Explorer視圖中看到如圖3-2所示的項目結構:
圖3-2 Eclipse中導入的Maven項目結構
我們看到主代碼目錄src/main/java和測試代碼目錄src/test/java成了Eclipse中的資源目錄,包和類的結構也十厘清晰,當然pom.xml永遠在項目的根目錄下,而從這個視圖中我們甚至還能看到項目的依賴junit-4.7.jar,其實際的位置指向了Maven本地倉庫(這裡我自定義了Maven本地倉庫位址為D:\java\repository,後續章節會介紹如何自定義本地倉庫位置)。
3.6.2 建立Maven項目
建立一個Maven項目也十分簡單,選擇菜單項File -> New -> Other,在彈出的對話框中選擇Maven下的Maven Project,然後點選Next >,在彈出的New Maven Project對話框中,我們使用預設的選項(不要選擇Create a simple project選項,那樣我們就能使用Maven Archetype),點選Next >,此時m2eclipse會提示我們選擇一個Archetype,我們選擇maven-archetype-quickstart,再點選Next >。由于m2eclipse實際上是在使用maven-archetype-plugin插件建立項目,是以這個步驟與上一節我們使用archetype建立項目骨架類似,輸入groupId,、artifactId、version、package(暫時我們不考慮Properties),如圖3-3所示:
圖3-3 在Eclipse中使用Archetype建立項目
注意,為了不和前面已導入的Hello World項目産生沖突和混淆,我們使用不同的artifactId和package。OK,點選Finish,Maven項目就建立完成了,其結構與前一個已導入的Hello World項目基本一緻。
3.6.3 運作mvn指令
我們需要在指令行輸入如mvn clean install之類的指令來執行maven建構,m2eclipse中也有對應的功能,在Maven項目或者pom.xml上右擊,再選擇Run As,就能看到如下的常見Maven指令,如圖3-4所示:
圖3-4 在Eclipse中運作預設mvn指令
選擇想要執行的Maven指令就能執行相應的建構,同時我們也能在Eclipse的console中看到建構輸出。這裡常見的一個問題是,預設選項中沒有我們想要執行的Maven指令怎麼辦?比如,預設帶有mvn test,但我們想執行mvn clean test,很簡單,選擇Maven buid… 以自定義Maven運作指令,在彈出對話框中的Goals一項中輸入我們想要執行的指令,如clean test,設定一下Name,點選Run即可。并且,下一次我們選擇Maven build,或者使用快捷鍵Alt + Shift + X, M快速執行Maven建構的時候,上次的配置直接就能在曆史記錄中找到。圖3-5就是自定義Maven運作指令的界面:
圖3-5 在Eclipse中自定義mvn指令
3.7 NetBeans Maven插件簡單使用
NetBeans的Maven插件也十分簡單易用,我們可以輕松地在NetBeans中導入現有的Maven項目,或者使用Archetype建立Maven項目,我們也能夠在NetBeans中直接運作mvn指令。
3.7.1 打開Maven項目
與其說打開Maven項目,不如稱之為導入更為合适,因為這個項目不需要是NetBeans建立的Maven項目,不過這裡我們還是遵照NetBeans菜單中使用的名稱。
選擇菜單欄中的檔案,然後選擇打開項目,直接定位到Hello World項目的根目錄,NetBeans會十分智能地識别出Maven項目,如圖3-6所示:
圖3-6 在NetBeans中導入Maven項目
Maven項目的圖示有别于一般的檔案夾,點選打開項目後,Hello World項目就會被導入到NetBeans中,在項目視圖中可以看到如圖3-7所示的項目結構:
圖3-7 NetBeans中導入的Maven項目結構
NetBeans中項目主代碼目錄的名稱為源包,測試代碼目錄成了測試包,編譯範圍依賴為庫,測試範圍依賴為測試庫,這裡我們也能看到pom.xml,NetBeans甚至還幫我們引用了settings.xml。
3.7.2 建立Maven項目
在NetBeans中建立Maven項目同樣十分輕松,在菜單欄中選擇檔案,然後建立項目,在彈出的對話框中,選擇項目類别為Maven,項目為Maven項目,點選“下一步”之後,對話框會提示我們選擇Maven原型(即Maven Archtype),我們選擇Maven快速啟動原型(1.0),(即前文提到的maven-archetype-quickstart),點選“下一步”之後,輸入項目的基本資訊,這些資訊在之前讨論archetype及在m2eclipse中建立Maven項目的時候都仔細解釋過,不再詳述,如圖3-8所示:
圖3-8 在NetBeans中使用Archetype建立Maven項目
點選完成之後,一個新的Maven項目就建立好了。
3.7.3 運作mvn指令
NetBeans在預設情況下提供兩種Maven運作方式,點選菜單欄中的運作,我們可以看到生成項目和清理并生成項目兩個選項,我們可以嘗試“點選運作Maven建構”,根據NetBeans控制台的輸出,我們就能發現它們實際上對應了mvn install和mvn clean install兩個指令。
在實際開發過程中,我們往往不會滿足于這兩種簡單的方式,比如,有時候我們隻想執行項目的測試,而不需要打包,這時我們就希望能夠執行mvn clean test指令,所幸的是NetBeans Maven插件完全支援自定義的mvn指令配置。
在菜單欄中選擇工具,接着選擇選項,在對話框中,最上面一欄選擇其他,下面選擇Maven标簽欄,在這裡我們可以對NetBeans Maven插件進行全局的配置(還記得第2章中我們如何配置NetBeans使用外部Maven麼?)。現在,選擇倒數第三行的編輯全局定制目标定義…,我們添加一個名為Maven Test的操作,執行目标為clean test,暫時不考慮其他配置選項,如圖3-9所示:
圖3-9 在NetBeans中自定義mvn指令
點選“預設儲存該配置”,在Maven項目上右擊,選擇定制,就能看到剛才配置好的Maven運作操作,選擇Maven Test之後,終端将執行mvn clean test。值得一提的是,我們也可以在項目上右擊,選擇定制,再選擇目标…再輸入想要執行的Maven目标(如clean package),點選确定之後NetBeans就會執行相應的Maven指令。這種方式十分便捷,但這是臨時的,該配置不會被儲存,也不會有曆史記錄。
3.8 小結
本章以盡可能簡單且詳細的方式叙述了一個Hello World項目,重點解釋了POM的基本内容、Maven項目的基本結構、以及建構項目基本的Maven指令。在此基礎上,還介紹了如何使用 Archetype快速建立項目骨架。最後講述的是如何在Eclipse和NetBeans中導入、建立及建構Maven項目。
原文連結:http://www.cnblogs.com/dcba1112/archive/2011/05/01/2033805.html