Maven 倉庫

f1uLove發表於2018-11-03

在 Maven 的術語中,倉庫是一個位置(place)。 Maven 倉庫是專案中依賴的第三方庫,這個庫所在的位置叫做倉庫。 在 Maven 中,任何一個依賴、外掛或者專案構建的輸出,都可以稱之為構件。 Maven 倉庫能幫助我們管理構件(主要是JAR),它就是放置所有JAR檔案(WAR,ZIP,POM等等)的地方。 Maven 倉庫有三種型別:

  • 本地(local)
  • 中央(central)
  • 遠端(remote)

###本地倉庫 Maven一個很突出的功能就是jar包管理,一旦工程需要依賴哪些jar包,只需要在Maven的pom.xml配置一下,該jar包就會自動引入工程目錄。初次聽來會覺得很神奇,下面我們來探究一下它的實現原理。

首先,這些jar包肯定不是沒爹沒孃的孩子,它們有來處,也有去處。集中儲存這些jar包(還有外掛等)的地方被稱之為倉庫(Repository)。 不管這些jar包從哪裡來的,必須儲存在自己的電腦裡之後,你的工程才能引用它們。類似於電腦裡有個客棧,專門款待這些遠道而來的客人,這個客棧就叫做本地倉庫。

比如,工程中需要依賴spring-core這個jar包,在pom.xml中宣告之後,maven會首先在本地倉庫中找,如果找到了很好辦,自動引入工程的依賴lib庫即可。可是,萬一找不到呢?實際上這種情況經常發生,尤其初次使用maven的時候,本地倉庫肯定是空無一物的,這時候就要靠maven大展神通,去遠端倉庫去下載。

預設情況下,不管Linux還是 Windows,每個使用者在自己的使用者目錄下都有一個路徑名為 .m2/respository/ 的倉庫目錄。 Maven 本地倉庫預設被建立在 使用者目錄下。要修改預設位置,在 Maven安裝目錄中的 conf資料夾下的 settings.xml 檔案中定義另一個路徑。

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 
   http://maven.apache.org/xsd/settings-1.0.0.xsd">
      <localRepository>C:/MyLocalRepository</localRepository>
</settings>
複製程式碼

中央倉庫

Maven 中央倉庫是由 Maven 社群提供的倉庫,其中包含了大量常用的庫。

中央倉庫包含了絕大多數流行的開源Java構件,以及原始碼、作者資訊、SCM、資訊、許可證資訊等。一般來說,簡單的Java專案依賴的構件都可以在這裡下載到。

中央倉庫的關鍵概念:

  • 這個倉庫由 Maven 社群管理。
  • 不需要配置。
  • 需要通過網路才能訪問。

要瀏覽中央倉庫的內容,maven 社群提供了一個 URL:search.maven.org/#browse。使用這個倉庫,開發人員可以搜尋所有可以獲取的程式碼庫。

遠端倉庫

如果 Maven 在中央倉庫中也找不到依賴的檔案,它會停止構建過程並輸出錯誤資訊到控制檯。為避免這種情況,Maven 提供了遠端倉庫的概念,它是開發人員自己定製倉庫,包含了所需要的程式碼庫或者其他工程中用到的 jar 檔案。

一般來講,公司都會通過自己的私有伺服器在區域網內架設一個倉庫代理。私服可以看作一種特殊的遠端倉庫,代理廣域網上的遠端倉庫,供區域網內的Maven使用者使用。當Maven需要下載構件的時候,先從私服請求,如果私服上不存在該構件,則從外部的遠端倉庫下載,快取在私服上之後,再為Maven的下載請求提供服務。

Maven 遠端倉庫
Maven私服有很多好處:

  • 可以把公司的私有jar包,以及無法從外部倉庫下載到的構件上傳到私服上,供公司內部使用;

  • 節省自己的外網頻寬:減少重複請求造成的外網頻寬消耗;

  • 加速Maven構建:如果專案配置了很多外部遠端倉庫的時候,構建速度就會大大降低;

  • 提高穩定性,增強控制:Internet不穩定的時候,maven構建也會變的不穩定,一些私服軟體還提供了其他的功能

當前主流的maven私服有Apache的Archiva、JFrog的Artifactory以及Sonatype的Nexus。

上面提到的中央倉庫、中央倉庫的映象倉庫、其他公共倉庫、私服都屬於遠端倉庫的範疇。

Maven 依賴搜尋順序

當我們執行 Maven 構建命令時,Maven 開始按照以下順序查詢依賴的庫:

1.在本地倉庫中搜尋,如果找不到,執行步驟 2,如果找到了則執行其他操作。 2.在中央倉庫中搜尋,如果找不到,並且有一個或多個遠端倉庫已經設定,則執行步驟 4,如果找到了則下載到本地倉庫中已被將來引用。 3.如果遠端倉庫沒有被設定,Maven 將簡單的停滯處理並丟擲錯誤(無法找到依賴的檔案)。 4.在一個或多個遠端倉庫中搜尋依賴的檔案,如果找到則下載到本地倉庫已被將來引用,否則 Maven 將停止處理並丟擲錯誤(無法找到依賴的檔案)。

倉庫的配置

倉庫配置要做兩件事,一是告訴maven你的本地倉庫在哪裡,二是你的遠端倉庫在哪裡。

顧名思義,setting.xm的第一個節點<localRepository>就是配置本地倉庫的地方,不用贅言。

遠端倉庫的配置有些複雜,因為會涉及很多附屬特性。下面以一切從實際出發,看看使用私服的情況下如何配置遠端倉庫。稍微像樣的公司都會建立自己的私服,如果一個公司連自己的私服都沒有(別管是因為買不起伺服器還是技術上做不到),你可以考慮一下跳槽的問題了。

現在最流行的maven倉庫管理器就是大名鼎鼎的Nexus(發音[ˈnɛksəs],英文中代表“中心、魔樞”的意思),它極大地簡化了自己內部倉庫的維護和外部倉庫的訪問。利用Nexus可以只在一個地方就能夠完全控制訪問和部署在你所維護倉庫中的每個Artifact。Nexus是一套“開箱即用”的系統不需要資料庫,它使用檔案系統加Lucene來組織資料。

至於Nexus怎麼部署,怎麼維護倉庫,作為開發人員是不需要關心的,只需要把Nexus私服的區域網地址寫入maven的本地配置檔案即可。具體的配置方法如下:

1、設定映象

<mirrors>
  <mirror>
       <!--該映象的唯一識別符號。id用來區分不同的mirror元素。 -->
       <id>nexus</id>
       <!-- 映象名,起註解作用,應做到見文知意。可以不配置  -->
       <name>Human Readable Name </name>
       <!--  所有倉庫的構件都要從映象下載  -->
       <mirrorOf>*</mirrorOf>
       <!-- 私服的區域網地址-->
       <url>http://192.168.0.1:8081/nexus/content/groups/public/</url> 
  </mirror>
</mirrors>
複製程式碼

節點<mirrors>下面可以配置多個映象,<mirrorOf>用於指明是哪個倉庫的映象,上例中使用萬用字元 * 表明該私服是所有倉庫的映象,不管本地使用了多少種遠端倉庫,需要下載構件時都會從私服請求。

如果只想將私服設定成某一個遠端倉庫的映象,使用<mirrorOf>指定該遠端倉庫的ID即可。

2、設定遠端倉庫 遠端倉庫的設定是在節點下面:

<repositories>
<repository>
    
   <!--倉庫唯一標識 -->
  <id>repoId </id>
    
   <!--遠端倉庫名稱  -->
  <name>repoName</name>
    
<!--遠端倉庫URL,如果該倉庫配置了映象,這裡的URL就沒有意義了,因為任何下載請求都會交由映象倉庫處理,前提是映象(也就是設定好的私服)需要確保該遠端倉庫裡的任何構件都能通過它下載到  -->
  <url>http://……</url>
 
   <!--如何處理遠端倉庫裡釋出版本的下載 -->
  <releases>
      
      <!--true或者false表示該倉庫是否為下載某種型別構件(釋出版,快照版)開啟。   -->
    <enabled>false</enabled>
      
      <!-- 該元素指定更新發生的頻率。Maven會比較本地POM和遠端POM的時間戳。這裡的選項是:-->
      <!-- always(一直),daily(預設,每日),interval:X(這裡X是以分鐘為單位的時間間隔),或者never(從不)。  -->
    <updatePolicy>always</updatePolicy>
      
      <!--當Maven驗證構件校驗檔案失敗時該怎麼做:-->
      <!--ignore(忽略),fail(失敗),或者warn(警告)。 -->
    <checksumPolicy>warn</checksumPolicy>
         
  </releases>
    
   <!--如何處理遠端倉庫裡快照版本的下載,與釋出版的配置類似 -->
  <snapshots>     
    <enabled/>
    <updatePolicy/>
    <checksumPolicy/>      
  </snapshots>
      
</repository>    
</repositories>
複製程式碼

可以配置多個遠端倉庫,用加以區分。

除此之外,還有一個與<repositories>並列存在<pluginRepositories>節點,用來配置外掛的遠端倉庫。

倉庫主要儲存兩種構件。第一種構件被用作其它構件的依賴,最常見的就是各類jar包。這是中央倉庫中儲存的大部分構件型別。另外一種構件型別是外掛,Maven外掛是一種特殊型別的構件。由於這個原因,外掛倉庫獨立於其它倉庫。<pluginRepositories>節點與<repositories>節點除了根節點的名字不一樣,子元素的結構與配置方法完全一樣:

<pluginRepositories>
      <pluginRepository>
 
             <id />
             <name />
             <url />
 
             <releases>
                    <enabled />
                    <updatePolicy />
                    <checksumPolicy />
             </releases>
                  
             <snapshots>
                    <enabled />
                    <updatePolicy />
                    <checksumPolicy />
             </snapshots>     
 
      </pluginRepository>             
</pluginRepositories>
複製程式碼

遠端倉庫有releasessnapshots兩組配置,POM就可以在每個單獨的倉庫中,為每種型別的構件採取不同的策略。例如,有時候會只為開發目的開啟對快照版本下載的支援,就需要把<releases>中的<enabled >設為false,而<snapshots>中的<enabled >設為true

由於遠端倉庫的配置是掛在<profile>節點下面,如果配置有多個<profile>節點,那麼就可能有多種遠端倉庫的設定方案,該方案是否生效是由它的父節點<profile>是否被啟用決定的。

3、設定釋出許可權 私服的作用除了可以給全公司的人提供maven構件的下載,還有一個非常重要的功能,就是開發者之間的資源共享。

一個大的專案往往是分模組進行開發的,各個模組之間存在依賴關係,比如一個交易系統,分為下單模組、支付模組、購物車模組等。現在開發下單模組的同學需要呼叫支付模組中的介面來完成支付功能,就需要將支付模組的某些jar包引入本地工程,才能呼叫它的介面;同時,開發購物車模組的同學需要呼叫下單模組的介面,來完成下單功能,他就需要依賴下單模組的某些jar包。這三個模組都在持續開發中,不可能將各自的原始碼傳來傳去支援對方的依賴。

解決的方式是這樣,每個模組完成了某個階段性的功能,都會將提供對外服務的介面打成jar包,傳到公司的私服當中,誰要使用該模組的功能,只需要在pom.xml檔案中宣告一下,maven就會像下載其他jar包那樣把它引入你的工程。

在開發過程中,在pom中宣告的構件版本一般是快照版:

<dependency>
      <groupId>com.yourCompany.trade</groupId>
      <artifactId>trade-pay</artifactId>
      <version>1.0.2-SNAPSHOT</version>
</dependency>
複製程式碼

各個模組會不斷的上傳新的jar包,如果本地專案依賴的是快照版,那麼maven一旦發現該jar包有新的釋出,就會將它下載下來替代以前的舊版本。比如,支付模組在測試的時候發現有個bug,修復了一下,然後將快照版釋出到私服。而你只需要專注於下單模組的開發,所依賴的支付模組的更新由maven處理,不需要關心。一旦你開發的模組修復了一個bug,或者新增了一個新功能等修改,只需要將釋出一次快照版本到私服即可,誰需要依賴你的介面誰自然會去私服下載,你也不用關心。 一般私服建立完畢之後不需要認證就可以訪問,但是風險會很大,這時就需要使用setting.xml中的servers元素了。需要注意的是,配置私服的資訊是在pom檔案中,但是認證資訊則是在setting.xml中,這是因為pom檔案往往是被提交到程式碼倉庫中供所有成員訪問的,而setting.xml是存放在本地的,這樣是安全的。

settings.xml中,配置具有釋出釋出版本和快照版本許可權的使用者:

server配置

上面的id是server的id,不是使用者登陸的id,該id與distributionManagement中repository元素的id相匹配。maven是根據pom中的repository和distributionMnagement元素來找到匹配的釋出地址:

專案配置

注意:pom中的id必須與setting.xml中配置好的id一致。

然後執行maven cleandeploy命令,將自己開發的構件部署在私服上供組織內其他使用者使用(maven clean deploy和maven clean install的區別:deploy是將該構件部署在私服中,而install是將構件存入自己的本地倉庫中)。

在這裡有人可能會有一個疑問,所有的倉庫設定不是已經在setting.xml中配置好了嗎,為什麼在pom的釋出管理節點當中還要配置一個url?

Setting.xml中配置的是你從哪裡下載構件,而這裡配置的是你要將構件釋出到哪裡。有時候可能下載用的倉庫與上傳用的倉庫是兩個地址,但是絕大多數情況下,兩者都是由私服充當,就是說兩者是同一個地址。

補充: Maven 倉庫預設在國外, 國內使用難免很慢,我們可以更換為阿里雲的倉庫。 第一步:修改 maven 根目錄下的 conf 資料夾中的 setting.xml 檔案,在 mirrors 節點上,新增內容如下:

<mirrors>
  <mirror>
    <id>alimaven</id>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <mirrorOf>central</mirrorOf>        
  </mirror>
</mirrors>
複製程式碼

第二步: pom.xml檔案裡新增:

<repositories>  
     <repository>  
           <id>alimaven</id>  
           <name>aliyun maven</name>  
           <url>http://maven.aliyun.com/nexus/content/groups/public/</url>  
           <releases>  
               <enabled>true</enabled>  
           </releases>  
           <snapshots>  
               <enabled>false</enabled>  
           </snapshots>  
     </repository>  
</repositories>
複製程式碼

Maven 的 Snapshot 版本與 Release 版本 1、Snapshot 版本代表不穩定、尚處於開發中的版本。 2、Release 版本則代表穩定的版本。 3、什麼情況下該用 SNAPSHOT? 協同開發時,如果 A 依賴構件 B,由於 B 會更新,B 應該使用 SNAPSHOT 來標識自己。這種做法的必要性可以反證如下:

  • a. 如果 B 不用 SNAPSHOT,而是每次更新後都使用一個穩定的版本,那版本號就會升得太快,每天一升甚至每個小時一升,這就是對版本號的濫用。
  • b.如果 B 不用 SNAPSHOT, 但一直使用一個單一的 Release 版本號,那當 B 更新後,A 可能並不會接受到更新。因為 A 所使用的 repository 一般不會頻繁更新 release 版本的快取(即本地 repository),所以B以不換版本號的方式更新後,A在拿B時發現本地已有這個版本,就不會去遠端Repository下載最新的 B

4、 不用 Release 版本,在所有地方都用 SNAPSHOT 版本行不行?
不行。正式環境中不得使用 snapshot 版本的庫。 比如說,今天你依賴某個 snapshot 版本的第三方庫成功構建了自己的應用,明天再構建時可能就會失敗,因為今晚第三方可能已經更新了它的 snapshot 庫。你再次構建時,Maven 會去遠端 repository 下載 snapshot 的最新版本,你構建時用的庫就是新的 jar 檔案了,這時正確性就很難保證了。

相關文章