之前我們說過Maven的版本分為快照和穩定版本,快照版本使用在開發的過程中,方便於團隊內部交流學習。而所說的穩定版本,理想狀態下是項目到了某個比較穩定的狀態,這個穩定包含了源代碼和構建都要穩定。
maven中的倉庫分為兩種,snapshot快照倉庫和release發布倉庫。snapshot快照倉庫用於保存開發過程中的不穩定版本,release正式倉庫則是用來保存穩定的發行版本。定義一個組件/模塊為快照版本,只需要在pom文件中在該模塊的版本號后加上-SNAPSHOT即可(注意這里必須是大寫)
maven2會根據模塊的版本號(pom文件中的version)中是否帶有-SNAPSHOT來判斷是快照版本還是正式版本。
如果是快照版本,那么在mvn deploy時會自動發布到快照版本庫中,會覆蓋老的快照版本,而在使用快照版本的模塊,在不更改版本號的情況下,
直接編譯打包時,maven會自動從鏡像服務器上下載最新的快照版本。如果是正式發布版本,那么在mvn deploy時會自動發布到正式版本庫中,
而使用正式版本的模塊,在不更改版本號的情況下,編譯打包時如果本地已經存在該版本的模塊則不會主動去鏡像服務器上下載。
使用SNAPSHOT具有透明性,變更會直接生效,但這樣會被依賴者帶來不穩定性和不確定性,所以不應該被濫用
補充:
對於服務,biz是沒有版本這一說的,運行的永遠都是最新的版本,但是對於API是有版本的。
API提供接口,biz提供服務,一般來說,版本往上升的話,API只增不減,而biz也隨之增加實現,如果新版本刪除了某個接口及實現,而調用者使用old version的依賴,嘗試調用這個接口,就會調不到產生錯誤。
Maven中建立的依賴管理方式基本已成為Java語言依賴管理的事實標准,Maven的替代者Gradle也基本沿用了Maven的依賴管理機制。在Maven依賴管理中,唯一標識一個依賴項是由該依賴項的三個屬性構成的,分別是groupId、artifactId以及version。這三個屬性可以唯一確定一個組件(Jar包或者War包)。
其實在Nexus倉庫中,一個倉庫一般分為public(Release)倉和SNAPSHOT倉,前者存放正式版本,后者存放快照版本。如果在項目配置文件中(無論是build.gradle還是pom.xml)指定的版本號帶有’-SNAPSHOT’后綴,比如版本號為’Junit-4.10-SNAPSHOT’,那么打出的包就是一個快照版本。
快照版本和正式版本的主要區別在於,本地獲取這些依賴的機制有所不同。假設你依賴一個庫的正式版本,構建的時候構建工具會先在本次倉庫中查找是否已經有了這個依賴庫,如果沒有的話才會去遠程倉庫中去拉取。所以假設你發布了Junit-4.10.jar到了遠程倉庫,有一個項目依賴了這個庫,它第一次構建的時候會把該庫從遠程倉庫中下載到本地倉庫緩存,以后再次構建都不會去訪問遠程倉庫了。所以如果你修改了代碼,向遠程倉庫中發布了新的軟件包,但仍然叫Junit-4.10.jar,那么依賴這個庫的項目就無法得到最新更新。你只有在重新發布的時候升級版本,比如叫做Junit-4.11.jar,然后通知依賴該庫的項目組也修改依賴版本為Junit-4.11,這樣才能使用到你最新添加的功能。
這種方式在團隊內部開發的時候會變的特別蛋痛。假設有兩個小組負責維護兩個組件,example-service和example-ui,其中example-ui項目依賴於example-service。而這兩個項目每天都會構建多次,如果每次構建你都要升級example-service的版本,那么你會瘋掉。這個時候SNAPSHOT版本就派上用場了。每天日常構建時你可以構建example-service的快照版本,比如example-service-1.0-SNAPSHOT.jar,而example-ui依賴該快照版本。每次example-ui構建時,會優先去遠程倉庫中查看是否有最新的example-service-1.0-SNAPSHOT.jar,如果有則下載下來使用。即使本地倉庫中已經有了example-service-1.0-SNAPSHOT.jar,它也會嘗試去遠程倉庫中查看同名的jar是否是最新的。有的人可能會問,這樣不就不能充分利用本地倉庫的緩存機制了嗎?別着急,Maven比我們想象中的要聰明。在配置Maven的Repository的時候中有個配置項,可以配置對於SNAPSHOT版本向遠程倉庫中查找的頻率。頻率共有四種,分別是always、daily、interval、never。當本地倉庫中存在需要的依賴項目時,always是每次都去遠程倉庫查看是否有更新,daily是只在第一次的時候查看是否有更新,當天的其它時候則不會查看;interval允許設置一個分鍾為單位的間隔時間,在這個間隔時間內只會去遠程倉庫中查找一次,never是不會去遠程倉庫中查找(這種就和正式版本的行為一樣了)。
Maven版本的配置方式為:
<repository> <id>myRepository</id> <url>...</url> <snapshots> <enabled>true</enabled> <updatePolicy>XXX</updatePolicy> </snapshots> </repository>
其中updatePolicy就是那4種類型之一。如果配置間隔時間更新,可以寫作interval:XX
(XX是間隔分鍾數)。daily配置是默認值。
而在Gradle,可以設置本地緩存的更新策略。
onfigurations.all {
// check for updates every build
resolutionStrategy.cacheChangingModulesFor 0,'seconds'
}
當然也可以按照分鍾或者小時來設置.
configurations.all { resolutionStrategy.cacheChangingModulesFor 10, ‘minutes' }
configurations.all { resolutionStrategy.cacheChangingModulesFor 4, ‘hours' }
所以一般在開發模式下,我們可以頻繁的發布SNAPSHOT版本,以便讓其它項目能實時的使用到最新的功能做聯調;當版本趨於穩定時,再發布一個正式版本,供正式使用。當然在做正式發布時,也要確保當前項目的依賴項中不包含對任何SNAPSHOT版本的依賴,保證正式版本的穩定性。
一、如何衡量項目的穩定狀態呢?
1. 所有的自動化測試應當全部通過
2. 項目沒有配置任何快照版本的依賴
3. 項目沒有配置任何快照版本的插件
4. 項目所包含的代碼都已經全部提交到了版本控制系統中
5.我們應當再一次執行Maven構建,以確保項目的狀態是OK的
6. 我們將這一次變更提交到版本控制的主干中,並打上標簽
只有滿足了上述6個條件, 我們就可以將這一個快照版本更新至發布版本
二、在開發的過程中,版本號要如何進行變更呢?Maven是否有潛在的約定?
我們在開發的過程中,下載jar包的時候經常會發現某個jar類似這樣:1.2.3-beat-4.jar
多么復雜的一個名稱。。。下面來解釋一下,這里每個數字的含義:
“ 1 ” : 表示該版本的第一個重大版本
“ 2 ” : 表示這是基於重大版本的第二個次要版本
“ 3 ” : 表示該次要版本的第三個增量
" beat-4" : 表示該增量的一個里程碑
用一個圖來描述:
< 主版本 > ------ < 次版本 > ------ < 增量版本 > ------ < 里程碑版本 >
主版本:表示了項目的重大架構變更 struts1 -- struts2
次版本:表示較大范圍的功能增加和變化 Nexus1.5 ---- Nexus1.4
增量版本:一般表示重大Bug修復
里程碑版本:指某一個版本的里程碑 *.*-alpha-1 *.*-beat-1
看起來有點麻煩啊, 但是在一般來說,我們只會聲明主版本和次版本,增量版本和里程碑版本就不一定了。
注:maven中約定的版本次序:
對於主版本、次版本、增量版本來說他們的比較是基於數字的,因此:1.5>1.4>1.3>1.2.11>1.2.8
對於里程碑版本來說,比較是基於字符串的,因此:1.5>1.4>1.3>1.2.3>1.2.11
三、主干、分支、標簽
上面的筆記中提到了主干和標簽,到底如何理解主干、分支、標簽呢?
主干: 項目開發代碼的主體,是從項目開始到當前都處於活動的狀態,從這里可以獲得項目最新的源代碼和幾乎所有的變更歷史
分支: 從主干的某個點分離出來的代碼拷貝,通常可以在不影響主干的前提下,在這里進行重大的bug修復或者實驗性質的開發,如果達到了預期的目的,通常將這里的變更合並到主干中去。
標簽: 用來標識主干或者分支的某個點的狀態,以代表項目的某個穩定狀態,也就是通常說的發布狀態
這三個元素,可以清晰的描述出項目的版本管理,而且也已經成了一個默認的行業標准。
四、自動化版本發布
用久了手動版本發布之后,我們會想到能否進行自動化的發布版本,答案是肯定的,這將引入一個新的插件:Maven Release Plugin
通過一些必要的配置,就可以完成版本發布
Maven Release Plugin 插件簡介:
該插件主要有三個目標:release: prepare, release: rollback, release: perform (什么是插件目標),在介紹分支自動化的時候還會引入branch目標
①release:prepare 准備版本發布,依次執行下列操作
1. 檢查項目是否有未提交的代碼
2. 檢查項目是否有快照版本依賴
3. 根據用戶的輸入將快照版本升級為發布版
4. 將POM中的SCM信息更新為標簽地址
5. 基於修改后的POM執行maven構建
6. 提交POM變更
7. 基於用戶輸入為代碼打標簽
8. 將代碼從發布版升級為新的快照版
9.提交POM變更
release: rollback
回退release: prepare所執行的操作。將POM回退至release:prepare之前的狀態,並提交。
注:該步驟不會刪除release:prepare生成的標簽,需要用戶手動刪除
release: perform
執行版本發布
簽出release:prepare生成的標簽中的源代碼,並在此基礎上執行mvn deploy命令打包並部署構件至倉庫
注:要為項目發布版本,首先需要為其添加正確的版本控制系統信息(這是因為Maven Release Plugin需要知道版本控制系統的主干、標簽等地址后才能執行相關操作)
②分支的自動化創建
先看一下Maven Release Plugin 的branch目標能幫助我們做哪些事情
1. 檢查本地有無未提交的代碼
2. 將分支更改POM的版本,如:1.1.0-SNAPSHOT改成1.1.1-SNAPSHOT
3. 將POM中的SCM信息更新為分支地址
4. 提交以上更改
5. 將主干代碼復制到分支中
6. 修改本地代碼使其回退到分支前的版本(用戶可以指定新的版本)
7. 提交本地更改
注:此時也必須正確的配置SCM信息
五、代碼安全
代碼安全是我們比較關心的一個問題, 比如說,當我們從中央倉庫下載第三方構件的時候,我們可能要去驗證這些文件的合法性,或者當我們發布項目后,使用我們項目的人也要驗證
引入一個新的插件:Maven GPG Plugin 自動的完成簽名
在使用Maven GPG Plugin之前,首先需要確定GPG是可用的,然后再POM中配置插件即可
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
然后使用一般的Maven命令簽名並發布項目構件
$mvn clean deploy -Dgpg.passphrase=****
注:
1. 如果不提供 -Dgpg.passphrase參數,運行時就會要求輸入密碼