Maven基礎教程之倉庫
前言
在前面的幾篇關於Maven的總結中,都說到只要指定了 groupId
、 artifactId
和 version
座標資訊,就可以從中央倉庫中找到對應的jar包。等一下,倉庫?大家肯定會問,倉庫是什麼?這個倉庫在哪裡?為什麼Maven會自動去那個倉庫找我要的jar包呢?好的,我知道大家肯定有一堆的疑問,一頭霧水,這篇文章就來解決大家的這些疑問,撥開疑霧,對這個“倉庫”一探究竟。跟著我的步伐,Let’s go!
Maven倉庫是什麼?
現在大家想一下之間開發的非Maven專案,是不是在每個專案下面都有一個lib目錄。是的,你不用去翻看你以前做的專案了,沒有錯,沒有Maven之前,我們專案依賴的包,我們都會下載下來,統一放到對應專案的lib目錄下去。同一個包,比如Spring框架的包,專案A要使用,就拷貝一份到專案A的lib目錄下去;專案B也要使用,那就再拷貝一份到專案B的目錄下去。這樣下去,你會發現同樣的依賴包,需要拷貝N份,這樣不僅造成了磁碟空間的浪費,而且也難於統一管理。
現在好了,有了Maven,基於Maven的座標機制,任何Maven專案使用任何一個構件的方式都是完全相同的。在此基礎上,Maven可以在某個位置統一儲存所有Maven專案共享的包,而這個統一存放依賴包的位置就是倉庫。說白了,Maven倉庫就是存放依賴包的地方。
有了這個Maven倉庫後,上面的問題就有了一個完美的解決方案。基於Maven開發的專案不再各自儲存其依賴檔案,它們只需要宣告這些依賴的座標,在需要的時候,Maven會自動根據座標找到倉庫中的包,並正確使用它們。
倉庫的分類
在使用Maven的過程中,我們需要知道Maven去哪裡找那個所謂的“倉庫”,從而載入依賴。所以,我們就需要知道Maven倉庫的分類。
在Maven中,倉庫分為以下兩類:
- 本地倉庫
- 遠端倉庫
Maven根據依賴座標去倉庫中找對應的包,是遵循這樣的一個軌跡:
- 首先去本地倉庫查詢,如果本地倉庫有對應的依賴包,則直接就使用;
- 如果本地倉庫不存在對應包時,或者需要檢視是否有更新的包版本時,Maven就會去遠端倉庫查詢,發現需要的構件之後,下載到本地倉庫在使用;
- 如果本地倉庫和遠端倉庫都沒有需要的包,Maven就會報錯。
上面簡單將Maven倉庫進行的分類,但是對於遠端倉庫,它又分為好幾種:
- 本地倉庫
上面也說到了Maven根據依賴座標去倉庫中找對應的包是有遵循的軌跡的。Maven最開始都是從本地倉庫尋找依賴的包。預設情況下,不管是在Windows還是在Linux上,每個使用者在自己的使用者目錄下都有一個路徑名為.m2/repository
的倉庫目錄。這個就是預設的本地倉庫地址。
有的時候,使用者可能會自定義本地倉庫的目錄地址(我一般都會這麼幹)。此時,可以通過編輯
~/.m2/settings.xml
,設定localRepository
元素的值就OK了,比如我的是這樣子的:<localRepository>E:/repository</localRepository>
這樣,該使用者的本地倉庫地址就被設定成了E:/repository。
-
中央倉庫
由於最開始的本地倉庫是空的,Maven必須知道至少一個可用的遠端倉庫,這樣才能在執行Maven命令的時候下載到需要的構件。中央倉庫就是這樣一個預設的遠端倉庫,Maven的安裝檔案中自帶了中央倉庫的配置。使用解壓縮工具開啟
$M2_HOME/lib/maven-model-builder-3.5.0.jar
檔案,在org\apache\maven\model
目錄下有一個pom-4.0.0.xml
檔案,該檔案裡面有這麼一段程式碼,它配置了預設的中央倉庫:<repositories> <repository> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
pom-4.0.0.xml檔案是所有Maven專案都會繼承的超級POM,這段配置使用id central對中央倉庫進行唯一標識,同時設定snapshots元素,其子元素enabled的值為false,表示不從該中央倉庫下載快照版本的包。
中央倉庫是一個大而全的包倉庫,它包含了這個世界上絕大多數流行的開源Java包,以及原始碼等資訊。一般來說,一個簡單Maven專案所需要的依賴包都能從中央倉庫下載到,這也就解釋了為什麼Maven能做到“開箱即用”。
-
私服
玩遊戲的時候,經常會聽到私服。但是在學習Maven的時候,也聽到私服,這個就比較特殊了。在Maven中,私服是一種特殊的遠端倉庫,它是架設在區域網內的倉庫服務,私服代理廣域網上的遠端倉庫,供區域網內的Maven使用者使用。整體架構如下圖所示:
當Maven需要下載依賴包的時候,它從私服請求,如果私服上不存在該依賴包,則從外部的遠端倉庫下載,快取到私服上之後,再為Maven的下載請求提供服務。另外,一些無法從外部倉庫下載到的依賴包也能從本地上傳到私服上供大家使用。
為啥要用私服呢?肯定是有少好處的。像在我們公司,在全國31個省都有分公司,同時總部研發中心還會開發一堆的公共JAR包,給31個分公司使用,這樣通過私服就可以很好的解決研發中心和分公司之間的公共包分發等問題。對於使用私服,它有以下這些優點:
- 加快Maven構建;我們知道,不停的連線外部倉庫下載依賴包是一件非常耗費時間的事情,而私服部署在區域網,則可以大大的降低依賴包的下載時間,提高Maven構建效率;
- 部署第三方包;比如我們公司的研發中心,會開發很多公共的包,而這些包又無法上傳至中央倉庫,所以這些包部署在私服就再適合不過了。
遠端倉庫配置
沒有一個平臺能夠大而全到包含所有的東西,同理,中央倉庫也是這樣的,雖然它包含了我們需要的大部分的依賴包,但是還是有一些包在中央倉庫中是找不到的。這個時候,我們就需要配置一些其它遠端倉庫來補充中央倉庫中沒有的依賴包,與中央倉庫配合完成工作,當中央倉庫也沒有對應的依賴包時,Maven則遍歷所有的遠端倉庫。
我們需要在pom.xml中配置即可,比如這樣:
<project> ...... <!-- 配置遠端倉庫 --> <repositories> <repository> <id>jboss</id> <name>JBoss Repository</name> <url>http://repository.jboss.com/maven2/</url> <releases> <enabled>true</enabled> <updatePolicy>daily</updatePolicy> </releases> <snapshots> <enabled>false</enabled> <checksumPolicy>warn</checksumPolicy> </snapshots> <layout>default</layout> </repository> </repositories> ...... </project>
-
repository
:在repositories
元素下,可以使用repository
子元素宣告一個或者多個遠端倉庫。 -
id
:倉庫宣告的唯一id,尤其需要注意的是,Maven自帶的中央倉庫使用的id為central,如果其他倉庫宣告也使用該id,就會覆蓋中央倉庫的配置。 -
name
:倉庫的名稱,讓我們直觀方便的知道倉庫是哪個,暫時沒發現其他太大的含義。 -
url
:指向了倉庫的地址,一般來說,該地址都基於http協議,Maven使用者都可以在瀏覽器中開啟倉庫地址瀏覽構件。 -
releases
和snapshots
:用來控制Maven對於釋出版構件和快照版構件的下載許可權。需要注意的是enabled子元素,該例中releases的enabled值為true,表示開啟JBoss倉庫的釋出版本下載支援,而snapshots的enabled值為false,表示關閉JBoss倉庫的快照版本的下載支援。根據該配置,Maven只會從JBoss倉庫下載釋出版的構件,而不會下載快照版的構件。 -
layout
:元素值default表示倉庫的佈局是Maven2及Maven3的預設佈局,而不是Maven1的佈局。基本不會用到Maven1的佈局。 -
其他:對於releases和snapshots來說,除了enabled,它們還包含另外兩個子元素updatePolicy和checksumPolicy。
元素updatePolicy用來配置Maven從遠處倉庫檢查更新的頻率,預設值是daily,表示Maven每天檢查一次。其他可用的值包括:never-從不檢查更新;always-每次構建都檢查更新;interval:X-每隔X分鐘檢查一次更新(X為任意整數)。
元素checksumPolicy用來配置Maven檢查校驗和檔案的策略。當構建被部署到Maven倉庫中時,會同時部署對應的檢驗和檔案。在下載構件的時候,Maven會驗證校驗和檔案,如果校驗和驗證失敗,當checksumPolicy的值為預設的warn時,Maven會在執行構建時輸出警告資訊,其他可用的值包括:fail-Maven遇到校驗和錯誤就讓構建失敗;ignore-使Maven完全忽略校驗和錯誤。
大部分公共的遠端倉庫無須認證就可以直接訪問,但我們在平時的開發中往往會架設自己的Maven遠端倉庫,出於安全方面的考慮,我們需要提供認證資訊才能訪問這樣的遠端倉庫。配置認證資訊和配置遠端倉庫不同,遠端倉庫可以直接在pom.xml中配置,但是認證資訊必須配置在settings.xml檔案中。這是因為pom往往是被提交到程式碼倉庫中供所有成員訪問的,而settings.xml一般只存在於本機。因此,在settings.xml中配置認證資訊更為安全。比如這樣配置:
<servers> <server> <id>deploymentRepo</id> <username>repouser</username> <password>repopwd</password> </server> </servers>
這裡的關鍵是id元素,settings.xml中server元素的id必須與pom.xml中需要認證的repository元素的id完全一致。正是這個id將認證資訊與倉庫配置聯絡在了一起。
部署至遠端倉庫
很多時候,我們編譯完成後,會將我們的負責的模組包部署至私服,以供其它團隊成員使用。那如何將我們的包部署到遠端倉庫呢?
我們配置專案的pom.xml檔案即可,配置如下所示:
<project> ...... <distributionManagement> <repository> <id>releases</id> <name>public</name> <url>http://59.50.95.66:8081/nexus/content/repositories/releases</url> </repository> <snapshotRepository> <id>snapshots</id> <name>Snapshots</name> <url>http://59.50.95.66:8081/nexus/content/repositories/snapshots</url> </snapshotRepository> </distributionManagement> ...... </project>
distributionManagement包含repository和snapshotRepository子元素,前者表示釋出版本(穩定版本)構件的倉庫,後者表示快照版本(開發測試版本)的倉庫。
配置正確後,執行 mvn clean deploy
命令,Maven就會將專案構建輸出的構件部署到配置對應的遠端倉庫,如果專案當前的版本是快照版本,則部署到快照版本的倉庫地址,否則就部署到釋出版本的倉庫地址。
快照版本
如果去你的本地倉庫,你可能會看到以這種類似於1.0.0、1.3-alpha-1、2.0、2.1-SNAPSHOT或者2.1-20190412.221213-52這樣的版本號命名的JAR包。其中,1.0.0、1.3-alpha-1和2.0是穩定的釋出版本,而2.1-SNAPSHOT和2.1-20190412.221213-52是不穩定的快照版本。
Maven為什麼要區分發布版本和快照版本呢?為什麼還要有2.1-SNAPSHOT和2.1-20190412.221213-52這樣的命名區分呢?
現在我們來思考一種現實的開發場景。現在軟體開發都是多人分模組開發,比如小明開發A模組,你開發B模組,而你的B模組是需要依賴A模組的,在開發過程中,小明需要經常將自己最新的程式碼提交編譯,生成A模組包,交給你,供你開發和整合除錯。這種開發場景,如何完美的實現多人協同開發、模組開發呢?
你可能想你自己每次單獨從程式碼更把A模組程式碼Pull下來,自己編譯,生成自己需要的依賴包。這麼做沒有問題,但是帶來的問題是你需要去拉程式碼,還要去編譯別人的模組,如果編譯不順利,各種錯誤,你可能一臉懵逼,只能去找小明解決了。這樣無形的就把工作流程搞砸了,你本來就只想要一個A模組的包,但是你卻幹了一堆不相干的事情,浪費時間。
你可能又想,小明每次將A模組編譯完成後,使用 mvn clean deploy
命令部署到私服,這樣你在編譯你的模組時,Maven就會自動的去私服下載對應的依賴包。想起來挺美的,但是在Maven中,同樣的版本和同樣的座標就意味著同樣的包,所以,如果你的本地倉庫中已經包含了模組A的某個版本的包,Maven就不會再對照遠端倉庫進行更新。除非你每次執行Maven命令之前,清除本地倉庫,但這種要求手工干預的做法顯然也是不可取的。
此時你可能又想,小明不斷的修改A模組的版本號,你也按照小明提供的版本號,修改A模組的依賴版本。是的,這樣是可以的,這就需要你和小明頻繁的修改POM,如果有更多的模組依賴,這個小問題就會變成一個大問題,而且還很容易出錯。
Maven的快照機制就是為了解決上述問題。在這個開發場景中,小明只需要將模組A的版本設定為 2.1-SNAPSHOT
,然後釋出到私服中,在釋出的過程中,Maven會自動為包打上時間戳。比如上面的 2.1-20190412.221213-52
就表示2019年4月12日22點12分13秒的第52次快照。有了這個時間戳,Maven就能隨時找到倉庫中該包 2.1-SNAPSHOT
版本最新的檔案。當你編譯B模組時,Maven會自動從倉庫中檢查模組A模組的 2.1-SNAPSHOT
的最新輸出包,當發現有更新時便進行下載。
基於快照版本機制,在不需要額外手工操作的情況下,就能完美的解決上述問題。在知道了快照的原理之後,我們的專案不應該依賴任何快照版本的依賴包,由於快照版本的不穩定性,這樣的依賴會造成潛在的危險。
映象
如果倉庫X可以提供倉庫Y儲存的所有內容,那麼就可以認為X是Y的一個映象。也就是說,任何一個可以從倉庫Y獲得的依賴包,都能夠從它的映象中獲取。比如 http://maven.aliyun.com/nexus/content/groups/public
是阿里提供的中央倉庫的映象,由於地理位置等其它因素,該映象往往能夠提供比中央倉庫更快的服務。因此,一般情況下,我們會配置映象來替代中央倉庫。編輯settings.xml檔案即可,比如配置阿里提供的映象:
<mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors>
mirrorOf
的值為central,表示該配置為中央倉庫的映象,任何對於中央倉庫的請求都會轉至該映象; id
、 name
和 url
的配置與一般倉庫配置一樣,表示該映象倉庫的唯一識別符號、名稱以及地址。
總結
回頭一看,Maven倉庫的知識點這麼多。這篇文章主要以理解性的知識點為主,很多內容都參考了網上的其它博文。這裡的知識點你不一定在使用Maven的過程中都會用到,但是理解了,就讓你以後的工作更加得心應手。不求都會,但求上面的內容你都看一遍,心中對Maven倉庫的概念和相關知識點有一個比較全面的理解和認識。全文讀完,用不了十分鐘。用十分鐘學習一個知識點,還是非常值得的。
果凍想,認真玩技術的地方。
2019年4月13日,於內蒙古呼和浩特。