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