1. 程式人生 > >maven快照版本和釋出版本

maven快照版本和釋出版本

   在使用maven過程中,我們在開發階段經常性的會有很多公共庫處於不穩定狀態,隨時需要修改併發布,可能一天就要釋出一次,遇到bug時,甚至一天要釋出N次。我們知道,maven的依賴管理是基於版本管理的,對於釋出狀態的artifact,如果版本號相同,即使我們內部的映象伺服器上的元件比本地新,maven也不會主動下載的。如果我們在開發階段都是基於正式釋出版本來做依賴管理,那麼遇到這個問題,就需要升級元件的版本號,可這樣就明顯不符合要求和實際情況了。但是,如果是基於快照版本,那麼問題就自熱而然的解決了,而maven已經為我們準備好了這一切。

      maven中的倉庫分為兩種,snapshot快照倉庫和release釋出倉庫。snapshot快照倉庫用於儲存開發過程中的不穩定版本,release正式倉庫則是用來儲存穩定的發行版本。定義一個元件/模組為快照版本,只需要在pom檔案中在該模組的版本號後加上-SNAPSHOT

即可(注意這裡必須是大寫),如下:

  1. <groupId>cc.mzone</groupId>
  2. <artifactId>m1</artifactId>
  3. <version>0.1-SNAPSHOT</version>
  4. <packaging>jar</packaging>

      maven2會根據模組的版本號(pom檔案中的version)中是否帶有-SNAPSHOT來判斷是快照版本還是正式版本。如果是快照版本,那麼在mvn deploy時會自動釋出到快照版本庫中,會覆蓋老的快照版本,而在使用快照版本的模組,在不更改版本號的情況下,直接編譯打包時,maven會自動從映象伺服器上下載最新的快照版本。如果是正式釋出版本,那麼在mvn deploy時會自動釋出到正式版本庫中,而使用正式版本的模組,在不更改版本號的情況下,編譯打包時如果本地已經存在該版本的模組則不會主動去映象伺服器上下載

      所以,我們在開發階段,可以將公用庫的版本設定為快照版本,而被依賴元件則引用快照版本進行開發,在公用庫的快照版本更新後,我們也不需要修改pom檔案提示版本號來下載新的版本,直接mvn執行相關編譯、打包命令即可重新下載最新的快照庫了,從而也方便了我們進行開發。

目前在JAVA的世界中,maven已經成為事實上的構建標準,很多開源庫的管理構建也是基於maven的,maven本身的學習曲線比較陡峭,遵循“約定優於配置”的理念,maven存在很多約定。本次我先描述下,關於版本的定義的選擇,SNAPSHOT or RELEASE?

版本之爭

在maven的約定中,依賴的版本分為兩類——SNAPSHOT和RELEASE。SNAPSHOT依賴泛指以-SNAPSHOT為結尾的版本號,例如1.0.1-SNAPSHOT。除此之外,所有非-SNAPSHOT結尾的版本號則都被認定為RELEASE版本,即正式版,雖然會有beta、rc之類說法,但是這些只是軟體工程角度的測試版,對於maven而言,這些都是RELEASE版本。既然Maven提供了這兩類版本號,那麼他們之前的優劣勢是什麼?分別在什麼場景下使用?

解讀SNAPSHOT

同一個SNAPSHOT版本的依賴可以多次釋出(deploy)到倉庫中,也就是說同一個SNAPSHOT版本的依賴可以在倉庫中存在多份,每一份都是程式碼在某一個特定時間的快照,這也是SNAPSHOT的含義。

如上圖,很好地表達了SNAPSHOT的細節,也闡述了一個SNAPSHOT很重要觀點——SNAPSHOT不是一個特定的版本,而是一系列的版本的集合,其中HEAD總是指向最新的快照,對外界可見的一般也是最新版,這種給人的假象是新的覆蓋了老的,從而使得使用SNAPSHOT依賴的客戶端總是通過重新構建(有時候需要-U強制更新)就可以拿到最新的程式碼。例如:A-->B-1.3.8-SNAPSHOT(理解為A依賴了B的1.3.8-SNAPSHOT版本),那麼B-1.3.8-SNAPSHOT更新之後重新deploy到倉庫之後,A只需要重新構建就可以拿到最新的程式碼,並不需要改變依賴B的版本。由此可見,這樣達到了變更傳達的透明性,這對於開發過程中的團隊協作的幫助不言而喻。

SNAPSHOT之殤

SNAPSHOT版本的依賴因為存在變更傳達的透明性的優勢而被賞識,甚至被“溺愛”,有很多團隊索性直接使用SNAPSHOT到生產環境中,這樣對於變更直接生效,很方便。但是作為技術人員的我們其實應該很嚴謹地看待變更傳達的透明性,變更就意味著風險,透明性更是把風險徹底隱藏了起來,生產環境中存在這樣的現象更是心驚膽戰。例如:A-->B.1.0.3-SNAPSHOT,B對一個A使用的功能實現進行了調整,直接釋出到倉庫,A重新構建或許就會失敗,更糟糕的是構建成功,執行時異常。這個時候A甚至完全沒有程式碼變更就突然失敗了,會帶來更多的困惑。

這也是maven經常遭人詬病的一個因素,對於同一份程式碼,構建結果卻不具備確定性,讓很多人沮喪。當然這個不完全是因為依賴的問題,也有maven外掛的問題,maven之前的版本尋找外掛策略的方式也存在不確定性,maven在版本2的時候,會去尋找最新的外掛版本(如果沒配置的話)來執行構建,經常會找到SNAPSHOT版本的外掛,所以依賴了一個不穩定的外掛來執行構建,不確定性就大大增加。不過maven在3版本就改變了這個策略,會尋找最新穩定版的外掛來執行構建,使得構建具備了確定性,穩定性也好多了。說明maven本身也在SNAPSHOT的問題上狠狠摔了一跤。

歸根到底,這些問題的根源就是SNAPSHOT是變化的,是不穩定的,而應用(軟體)依賴於變化並且不穩定的SNAPSHOT的依賴會導致自身也在變化和不穩定中,這是穩定性的一個大忌,依賴不穩定的服務或者依賴,上述的maven2的問題就是一個典型反例。

RELEASE簡介

RELEASE版本和SNAPSHOT是相對的,非SANPSHOT版本即RELEASE版本,RELEASE版本是一個穩定的版本號,看清楚咯,是一個,不是一系列,可以認為RELEASE版本是不可變化的,一旦釋出,即永遠不會變化。

雖然RELEASE版本是穩定不變的,但是倉庫還是有策略讓這個原則變得可配置,有的倉庫會配置成redeploy覆蓋,這樣RELEASE版本就變成SNAPSHOT了,偽裝成RELEASE的SNAPSHOT,會讓問題更費解和棘手,我一般稱這類人為“挖坑專家”。

記住,RELEASE一旦釋出,就不可改變。

如何選擇

那麼什麼時候使用SNAPSHOT?什麼時候使用RELEASE?這個可以從他們各自的特性上來看,SNAPSHOT版本的庫是一直在變化的,或者說隨時都會變化的,這樣雖然可以獲取到最新的特性,但是也存在不穩定因素,依賴一個不穩定的模組或者庫會讓模組自身也變得不穩定,尤其是自身對被依賴模組的變化超出掌控的情況。即使可以掌控被依賴模組的變化,也會帶來不穩定的因素,因為每次變更都有引入bug的可能性。如果這麼說,那麼我們是不是要摒棄SANPSHOT了呢?答案肯定是否定的。

想象下,什麼情況下,模組會一直變化或者變化比較劇烈?開發新特性的時候,所以對於團隊之間協同開發的時候,模組之間出現依賴,變化會非常劇烈,如模組A依賴模組B,模組A必然需要最方便地獲取模組B的特性,在開發期間,方便性比穩定性更重要。可以反證下,假設模組B使用RELEASE版本1.0.0,模組A依賴1.0.0,現在模組A出現了bug,需要修復下,那麼A就要提供一個版本號1.0.1,這樣所有依賴A模組都需要更新版本號,因為開發期間這種事情是如此多,所以會帶來鉅變。反觀SNAPSHOT方案,如果模組B的版本是1.0.0-SNAPSHOT,模組A完全不需要修改版本號即可獲取模組B的新特性。當開發進入預釋出階段,為了生產環境的穩定性,依賴應該是RELEASE版本,因為此時SNAPSHOT版本的模組自動獲取新特性的特點恰恰會造成生產環境的不穩定性,生產環境上,穩定性重於一切。

魔幻之手

現在已經很明確了,在開發期間,活躍模組的版本號使用SNAPSHOT,在生產期間,依賴RELEASE版本模組。貌似,我們找到了銀彈,不過這個只是理想狀態,即所有的模組的版本都在自己的掌控或者間接掌控下,只有這樣你才能影響對應模組的版本號。往往是理想很豐滿,現實卻很骨感,如果你依賴的一個模組只有SNAPSHOT版本,並且該模組也很活躍,最無助的是模組的維護人不理會你的請求,那麼是否就沒轍了,只能把應用構建在不穩定模組上呢?介紹一款maven外掛——versions,這是一個非常強大的版本管理外掛,其中有個對依賴版本加鎖的特性——lock-snapshots,並且提供了引數可以控制鎖定的依賴,就可以實現對特定的SNAPSHOT模組鎖定版本,執行的命令如下:mvn versions:lock-snapshots -DincludesList="groupId:artifactId:type:classifier:version",執行這個命令之後,對應的版本號會變化,比如1.0.0-SNAPSHOT會變成1.0.0.20090327.172306-4,即完成了鎖定,此時這個SNAPSHOT就變成了固定小版本的穩定版本,不會在變化了,也相當於正式版的功能了。當然以後也可以解鎖,詳細請看對應文件。