许晓斌_Maven实战(一)——坐标规划
from:http://www.infoq.com/cn/news/2010/12/xxb-maven-1
坐標是什么?為什么要規劃?
坐標是Maven最基本的概念,它就像每個構件的身份證號碼,有了它我們就可以在數以千萬計的構件中定位任何一個我們感興趣的構件。舉個最簡單的例子,如果沒有坐標,使用JUnit的時候,用戶就需要去下載依賴jar包,用依賴的方式,簡單配置使用如junit:junit:4.8.2就可以了。這里第一個junit是groupId,第二個junit是artifactId,4.8.2是version。
Maven的很多其他核心機制都依賴于坐標,其中最顯著的就是倉庫和依賴管理。對于倉庫來說,有了坐標就知道在什么位置存儲構件的內容,例如junit:junit:4.8.2就對應倉庫中的路徑/junit/junit/4.8.2/junit-4.8.2.pom和/junit/junit/4.8.2/junit-4.8.2.jar這樣的文件,讀者可以直接訪問中央倉庫地址看到這樣的倉庫布局,或者瀏覽本地倉庫目錄~/.m2/repository/以獲得直觀的體驗。
依賴的配置也是完全基于坐標的,例如:
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.8.2</version><scope>test</scope> </dependency>有了正確的坐標,Maven才能夠在正確的位置找到依賴文件并使用,這里值為test的scope是用來控制該依賴只在測試時可用,與坐標無關。
正因為坐標是Maven核心的核心,因此規劃正確的坐標至關重要,如果你使用了模糊不清的坐標,那么你的用戶就很難找到你的構件,或者即使找到了,也容易寫錯。錯誤的使用坐標,還會造成沖突,如果你也使用junit這樣的groupId,那會發生什么?下面先看一些不是很規范的坐標使用方式。
坐標規劃的原則
濫用坐標、錯用坐標的樣例比比皆是,在中央倉庫中我們能看到SpringFramework有兩種坐標,其一是直接使用springframework作為groupId,如springframework:spring-beans:1.2.6,另一種是用org.springframework作為groupId,如org.springframework:spring-beans:2.5。細心看看,前一種方式顯得比較隨意,后一種方式則是基于域名衍生出來的,顯然后者更合理,因為用戶能一眼根據域名聯想到其Maven坐標,方便尋找。因此新版本的SpringFramework構件都使用org.springframework作為groupId。由這個例子我們可以看到坐標規劃一個原則是基于項目域名衍生。其實很多流行的開源項目都破壞了這個原則,例如JUnit,這是因為Maven社區在最開始接受構件并部署到中央倉庫的時候,沒有很很嚴格的限制,而對于這些流行的項目來說,一時間更改坐標會影響大量用戶,因此也算是個歷史遺留問題了。
還有一個常見的問題是將groupId直接匹配到公司或者組織名稱,因為乍一看這是顯而易見的。例如組織是zoo.com,有個項目是dog,那有些人就直接使用groupId com.zoo了。如果項目只有一個模塊,這是沒有什么問題的,但現實世界的項目往往會有很多模塊,Maven的一大長處就是通過多模塊的方式管理項目。那dog項目可能會有很多模塊,我們用坐標的哪個部分來定義模塊呢?groupId顯然不對,version也不可能是,那只有artifactId。因此要這里有了另外一個原則,用artifactId來定義模塊,而不是定義項目。接下來,很顯然的,項目就必須用groupId來定義。因此對于dog項目來說,應該使用groupId com.zoo.dog,不僅體現出這是zoo.com下的一個項目,而且可以與該組織下的其他項目如com.zoo.cat區分開來。
除此之外,artifactId的定義也有最佳實踐,我們常??梢钥吹揭粋€項目有很多的模塊,例如api,dao,service,web等等。Maven項目在默認情況下生成的構件,其名稱不會是基于artifactId,version和packaging生成的,例如api-1.0.jar,dao-1.0.jar等等,他們不會帶有groupId的信息,這會造成一個問題,例如當我們把所有這些構件放到Web容器下的時候,你會發現項目dog有api-1.0.jar,項目cat也有api-1.0.jar,這就造成了沖突。更壞的情況是,dog項目有api-1.0.jar,cat項目有api-2.0.jar,其實兩者沒什么關系,可當放在一起的時候,卻很容易讓人混淆。為了讓坐標更加清晰,又出現了一個原則,即在定義artiafctId時也加入項目的信息,例如dog項目的api模塊,那就使用artifactId dog-api,其他就是dog-dao,dao-service等等。雖然連字號是不允許出現在Java的包名中的,但Maven沒這個限制?,F在dog-api-1.0.jar,cat-2.0.jar被放在一起時,就不容易混淆了。
關于坐標,我們還沒談到version,這里不再詳述因為讀者可以從Maven: The Complete Guide中找到詳細的解釋,簡言之就是使用這樣一個格式:
<主版本>.<次版本>.<增量版本>-<限定符>其中主版本主要表示大型架構變更,次版本主要表示特性的增加,增量版本主要服務于bug修復,而限定符如alpha、beta等等是用來表示里程碑。當然不是每個項目的版本都要用到這些4個部分,根據需要選擇性的使用即可。在此基礎上Maven還引入了SNAPSHOT的概念,用來表示活動的開發狀態,由于不涉及坐標規劃,這里不進行詳述。不過有點要提醒的是,由于SNAPSHOT的存在,自己顯式地在version中使用時間戳字符串其實沒有必要。
Classifier
Classifier可能是最容易被忽略的Maven特性,但它確實非常重要,我們也需要它來幫助規劃坐標。設想這樣一個情況,有一個jar項目,就說是?dog-cli-1.0.jar?吧,運行它用戶就能在命令行上畫一只小狗出來。現在用戶的要求是希望你能提供一個zip包,里面不僅包含這個可運行的jar,還得包含源代碼和文檔,換句話說,這是比較正式的分發包。這個文件名應該是怎樣的呢?dog-cli-1.0.zip?不夠清楚,僅僅從擴展名很難分辨什么是Maven默認生成的構件,什么是額外配置生成分發包。如果能是dog-cli-1.0-dist.zip就最好了。這里的dist就是classifier,默認Maven只生成一個構件,我們稱之為主構件,那當我們希望Maven生成其他附屬構件的時候,就能用上classifier。常見的classifier還有如dog-cli-1.0-sources.jar表示源碼包,dog-cli-1.0-javadoc.jar表示JavaDoc包等等。制作classifier的方式多種多樣,其中最重要的一種是使用Maven Assembly Plugin,感興趣的讀者可以進一步研究。
小結
本文是InfoQ Maven專欄的第一篇,討論的是Maven坐標的規劃,包括如何正確的使用groupId、artifactId、version,以及classfier。筆者在維護Maven中央倉庫的工作過程中遇到過各種各樣模糊的甚至是錯誤的坐標,它們的存在給廣大Maven用戶帶來的極大的不便。本文拋出一些較好的實踐,幫助大家更好的使用Maven。如果讀者有相關的經驗總結,也請不吝分享。
關于作者
許曉斌(Juven Xu),國內社區公認的Maven技術專家、Maven中文用戶組創始人、Maven技術的先驅和積極推動者。對Maven有深刻的認識,實戰經驗豐富,不僅撰寫了大量關于Maven的技術文章,而且還翻譯了開源書籍《Maven權威指南》,對Maven技術在國內的普及和發展做出了很大的貢獻。就職于Maven之父的公司,負責維護Maven中央倉庫,是Maven倉庫管理器Nexus(著名開源軟件)的核心開發者之一,曾多次受邀到淘寶等大型企業開展Maven方面的培訓。此外,他還是開源技術的積極倡導者和推動者,擅長Java開發和敏捷開發實踐。他的個人網站是:http://www.juvenxu.com。
【編者按】InfoQ中文站有幸邀請到Sonotype(Maven背后的公司)在中國唯一的員工、《Maven實戰》的作者許曉斌先生,在InfoQ中文站開辟Maven的專欄,為開發者帶來一些Maven的高級話題,以及他積累多年的Maven經驗分享。
總結
以上是生活随笔為你收集整理的许晓斌_Maven实战(一)——坐标规划的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MPLS排错练习题分享
- 下一篇: 该如何去认知Level 2 十档行情数据