maven快照版本和发布版本
在使用maven過程中,我們?cè)陂_發(fā)階段經(jīng)常性的會(huì)有很多公共庫處于不穩(wěn)定狀態(tài),隨時(shí)需要修改并發(fā)布,可能一天就要發(fā)布一次,遇到bug時(shí),甚至一天要發(fā)布N次。我們知道,maven的依賴管理是基于版本管理的,對(duì)于發(fā)布狀態(tài)的artifact,如果版本號(hào)相同,即使我們內(nèi)部的鏡像服務(wù)器上的組件比本地新,maven也不會(huì)主動(dòng)下載的。如果我們?cè)陂_發(fā)階段都是基于正式發(fā)布版本來做依賴管理,那么遇到這個(gè)問題,就需要升級(jí)組件的版本號(hào),可這樣就明顯不符合要求和實(shí)際情況了。但是,如果是基于快照版本,那么問題就自熱而然的解決了,而maven已經(jīng)為我們準(zhǔn)備好了這一切。
?? ? ?maven中的倉庫分為兩種,snapshot快照倉庫和release發(fā)布倉庫。snapshot快照倉庫用于保存開發(fā)過程中的不穩(wěn)定版本,release正式倉庫則是用來保存穩(wěn)定的發(fā)行版本。定義一個(gè)組件/模塊為快照版本,只需要在pom文件中在該模塊的版本號(hào)后加上-SNAPSHOT即可(注意這里必須是大寫),如下:
<groupId>cc.mzone</groupId>
<artifactId>m1</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>
?? ? ?maven2會(huì)根據(jù)模塊的版本號(hào)(pom文件中的version)中是否帶有-SNAPSHOT來判斷是快照版本還是正式版本。如果是快照版本,那么在mvn deploy時(shí)會(huì)自動(dòng)發(fā)布到快照版本庫中,會(huì)覆蓋老的快照版本,而在使用快照版本的模塊,在不更改版本號(hào)的情況下,直接編譯打包時(shí),maven會(huì)自動(dòng)從鏡像服務(wù)器上下載最新的快照版本。如果是正式發(fā)布版本,那么在mvn deploy時(shí)會(huì)自動(dòng)發(fā)布到正式版本庫中,而使用正式版本的模塊,在不更改版本號(hào)的情況下,編譯打包時(shí)如果本地已經(jīng)存在該版本的模塊則不會(huì)主動(dòng)去鏡像服務(wù)器上下載。
?? ? ?所以,我們?cè)陂_發(fā)階段,可以將公用庫的版本設(shè)置為快照版本,而被依賴組件則引用快照版本進(jìn)行開發(fā),在公用庫的快照版本更新后,我們也不需要修改pom文件提示版本號(hào)來下載新的版本,直接mvn執(zhí)行相關(guān)編譯、打包命令即可重新下載最新的快照庫了,從而也方便了我們進(jìn)行開發(fā)。
?
目前在JAVA的世界中,maven已經(jīng)成為事實(shí)上的構(gòu)建標(biāo)準(zhǔn),很多開源庫的管理構(gòu)建也是基于maven的,maven本身的學(xué)習(xí)曲線比較陡峭,遵循“約定優(yōu)于配置”的理念,maven存在很多約定。本次我先描述下,關(guān)于版本的定義的選擇,SNAPSHOT or RELEASE?
版本之爭(zhēng)
在maven的約定中,依賴的版本分為兩類——SNAPSHOT和RELEASE。SNAPSHOT依賴泛指以-SNAPSHOT為結(jié)尾的版本號(hào),例如1.0.1-SNAPSHOT。除此之外,所有非-SNAPSHOT結(jié)尾的版本號(hào)則都被認(rèn)定為RELEASE版本,即正式版,雖然會(huì)有beta、rc之類說法,但是這些只是軟件工程角度的測(cè)試版,對(duì)于maven而言,這些都是RELEASE版本。既然Maven提供了這兩類版本號(hào),那么他們之前的優(yōu)劣勢(shì)是什么?分別在什么場(chǎng)景下使用?
解讀SNAPSHOT
同一個(gè)SNAPSHOT版本的依賴可以多次發(fā)布(deploy)到倉庫中,也就是說同一個(gè)SNAPSHOT版本的依賴可以在倉庫中存在多份,每一份都是代碼在某一個(gè)特定時(shí)間的快照,這也是SNAPSHOT的含義。
如上圖,很好地表達(dá)了SNAPSHOT的細(xì)節(jié),也闡述了一個(gè)SNAPSHOT很重要觀點(diǎn)——SNAPSHOT不是一個(gè)特定的版本,而是一系列的版本的集合,其中HEAD總是指向最新的快照,對(duì)外界可見的一般也是最新版,這種給人的假象是新的覆蓋了老的,從而使得使用SNAPSHOT依賴的客戶端總是通過重新構(gòu)建(有時(shí)候需要-U強(qiáng)制更新)就可以拿到最新的代碼。例如:A-->B-1.3.8-SNAPSHOT(理解為A依賴了B的1.3.8-SNAPSHOT版本),那么B-1.3.8-SNAPSHOT更新之后重新deploy到倉庫之后,A只需要重新構(gòu)建就可以拿到最新的代碼,并不需要改變依賴B的版本。由此可見,這樣達(dá)到了變更傳達(dá)的透明性,這對(duì)于開發(fā)過程中的團(tuán)隊(duì)協(xié)作的幫助不言而喻。
SNAPSHOT之殤
SNAPSHOT版本的依賴因?yàn)榇嬖谧兏鼈鬟_(dá)的透明性的優(yōu)勢(shì)而被賞識(shí),甚至被“溺愛”,有很多團(tuán)隊(duì)索性直接使用SNAPSHOT到生產(chǎn)環(huán)境中,這樣對(duì)于變更直接生效,很方便。但是作為技術(shù)人員的我們其實(shí)應(yīng)該很嚴(yán)謹(jǐn)?shù)乜创兏鼈鬟_(dá)的透明性,變更就意味著風(fēng)險(xiǎn),透明性更是把風(fēng)險(xiǎn)徹底隱藏了起來,生產(chǎn)環(huán)境中存在這樣的現(xiàn)象更是心驚膽戰(zhàn)。例如:A-->B.1.0.3-SNAPSHOT,B對(duì)一個(gè)A使用的功能實(shí)現(xiàn)進(jìn)行了調(diào)整,直接發(fā)布到倉庫,A重新構(gòu)建或許就會(huì)失敗,更糟糕的是構(gòu)建成功,運(yùn)行時(shí)異常。這個(gè)時(shí)候A甚至完全沒有代碼變更就突然失敗了,會(huì)帶來更多的困惑。
這也是maven經(jīng)常遭人詬病的一個(gè)因素,對(duì)于同一份代碼,構(gòu)建結(jié)果卻不具備確定性,讓很多人沮喪。當(dāng)然這個(gè)不完全是因?yàn)橐蕾嚨膯栴},也有maven插件的問題,maven之前的版本尋找插件策略的方式也存在不確定性,maven在版本2的時(shí)候,會(huì)去尋找最新的插件版本(如果沒配置的話)來執(zhí)行構(gòu)建,經(jīng)常會(huì)找到SNAPSHOT版本的插件,所以依賴了一個(gè)不穩(wěn)定的插件來執(zhí)行構(gòu)建,不確定性就大大增加。不過maven在3版本就改變了這個(gè)策略,會(huì)尋找最新穩(wěn)定版的插件來執(zhí)行構(gòu)建,使得構(gòu)建具備了確定性,穩(wěn)定性也好多了。說明maven本身也在SNAPSHOT的問題上狠狠摔了一跤。
歸根到底,這些問題的根源就是SNAPSHOT是變化的,是不穩(wěn)定的,而應(yīng)用(軟件)依賴于變化并且不穩(wěn)定的SNAPSHOT的依賴會(huì)導(dǎo)致自身也在變化和不穩(wěn)定中,這是穩(wěn)定性的一個(gè)大忌,依賴不穩(wěn)定的服務(wù)或者依賴,上述的maven2的問題就是一個(gè)典型反例。
RELEASE簡(jiǎn)介
RELEASE版本和SNAPSHOT是相對(duì)的,非SANPSHOT版本即RELEASE版本,RELEASE版本是一個(gè)穩(wěn)定的版本號(hào),看清楚咯,是一個(gè),不是一系列,可以認(rèn)為RELEASE版本是不可變化的,一旦發(fā)布,即永遠(yuǎn)不會(huì)變化。
雖然RELEASE版本是穩(wěn)定不變的,但是倉庫還是有策略讓這個(gè)原則變得可配置,有的倉庫會(huì)配置成redeploy覆蓋,這樣RELEASE版本就變成SNAPSHOT了,偽裝成RELEASE的SNAPSHOT,會(huì)讓問題更費(fèi)解和棘手,我一般稱這類人為“挖坑專家”。
記住,RELEASE一旦發(fā)布,就不可改變。
如何選擇
那么什么時(shí)候使用SNAPSHOT?什么時(shí)候使用RELEASE?這個(gè)可以從他們各自的特性上來看,SNAPSHOT版本的庫是一直在變化的,或者說隨時(shí)都會(huì)變化的,這樣雖然可以獲取到最新的特性,但是也存在不穩(wěn)定因素,依賴一個(gè)不穩(wěn)定的模塊或者庫會(huì)讓模塊自身也變得不穩(wěn)定,尤其是自身對(duì)被依賴模塊的變化超出掌控的情況。即使可以掌控被依賴模塊的變化,也會(huì)帶來不穩(wěn)定的因素,因?yàn)槊看巫兏加幸隻ug的可能性。如果這么說,那么我們是不是要摒棄SANPSHOT了呢?答案肯定是否定的。
想象下,什么情況下,模塊會(huì)一直變化或者變化比較劇烈?開發(fā)新特性的時(shí)候,所以對(duì)于團(tuán)隊(duì)之間協(xié)同開發(fā)的時(shí)候,模塊之間出現(xiàn)依賴,變化會(huì)非常劇烈,如模塊A依賴模塊B,模塊A必然需要最方便地獲取模塊B的特性,在開發(fā)期間,方便性比穩(wěn)定性更重要。可以反證下,假設(shè)模塊B使用RELEASE版本1.0.0,模塊A依賴1.0.0,現(xiàn)在模塊A出現(xiàn)了bug,需要修復(fù)下,那么A就要提供一個(gè)版本號(hào)1.0.1,這樣所有依賴A模塊都需要更新版本號(hào),因?yàn)殚_發(fā)期間這種事情是如此多,所以會(huì)帶來巨變。反觀SNAPSHOT方案,如果模塊B的版本是1.0.0-SNAPSHOT,模塊A完全不需要修改版本號(hào)即可獲取模塊B的新特性。當(dāng)開發(fā)進(jìn)入預(yù)發(fā)布階段,為了生產(chǎn)環(huán)境的穩(wěn)定性,依賴應(yīng)該是RELEASE版本,因?yàn)榇藭r(shí)SNAPSHOT版本的模塊自動(dòng)獲取新特性的特點(diǎn)恰恰會(huì)造成生產(chǎn)環(huán)境的不穩(wěn)定性,生產(chǎn)環(huán)境上,穩(wěn)定性重于一切。
魔幻之手
現(xiàn)在已經(jīng)很明確了,在開發(fā)期間,活躍模塊的版本號(hào)使用SNAPSHOT,在生產(chǎn)期間,依賴RELEASE版本模塊。貌似,我們找到了銀彈,不過這個(gè)只是理想狀態(tài),即所有的模塊的版本都在自己的掌控或者間接掌控下,只有這樣你才能影響對(duì)應(yīng)模塊的版本號(hào)。往往是理想很豐滿,現(xiàn)實(shí)卻很骨感,如果你依賴的一個(gè)模塊只有SNAPSHOT版本,并且該模塊也很活躍,最無助的是模塊的維護(hù)人不理會(huì)你的請(qǐng)求,那么是否就沒轍了,只能把應(yīng)用構(gòu)建在不穩(wěn)定模塊上呢?介紹一款maven插件——versions,這是一個(gè)非常強(qiáng)大的版本管理插件,其中有個(gè)對(duì)依賴版本加鎖的特性——lock-snapshots,并且提供了參數(shù)可以控制鎖定的依賴,就可以實(shí)現(xiàn)對(duì)特定的SNAPSHOT模塊鎖定版本,執(zhí)行的命令如下:mvn versions:lock-snapshots -DincludesList="groupId:artifactId:type:classifier:version",執(zhí)行這個(gè)命令之后,對(duì)應(yīng)的版本號(hào)會(huì)變化,比如1.0.0-SNAPSHOT會(huì)變成1.0.0.20090327.172306-4,即完成了鎖定,此時(shí)這個(gè)SNAPSHOT就變成了固定小版本的穩(wěn)定版本,不會(huì)在變化了,也相當(dāng)于正式版的功能了。當(dāng)然以后也可以解鎖,詳細(xì)請(qǐng)看對(duì)應(yīng)文檔。
總結(jié)
以上是生活随笔為你收集整理的maven快照版本和发布版本的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nomad入门
- 下一篇: Alpine Linux 使用简介