天天看點

《Maven實戰》閱讀總結(二)Maven倉庫

(五)Maven倉庫

Maven倉庫

在Maven世界中,任何一個依賴、插件或者項目建構的輸出,都可以成為構件(jar、war包等)。

Maven在某個位置上統一存儲所有Maven項目共享的構件,即為Maven倉庫;

Maven項目不用各自存儲依賴檔案,隻需聲明依賴的坐标,在需要時(編譯、運作、打包),Maven會自動根據坐标找到Maven倉庫中的構件,并使用它們。

倉庫的布局

在Maven世界中,任何一個構件都有其唯一的坐标,通過坐标可以定義其在倉庫中的唯一存儲路徑,即Maven的倉庫布局方式。

Maven構件的存儲路徑為:groupId/artifactId/version/artifactId-version[-classifier].packaging

Ps(個人了解): 倉庫的布局方式就是定義了坐标與構件路徑的對應關系,即如何通過坐标找到構件。

倉庫的分類

對Maven而言,倉庫隻分為兩類,本地倉庫、遠端倉庫。而遠端倉庫又可細分為中央倉庫、私服、其他公共庫。

當Maven根據坐标尋找構件時,首先檢視本地倉庫,如果不存在,Maven就會去遠端倉庫查找并下載下傳到本地檔案。如果都沒有,Maven就會報錯。分類如下圖

《Maven實戰》閱讀總結(二)Maven倉庫

1 本地倉庫

通常Maven項目目錄下,沒有諸如lib/這樣存放依賴檔案的目錄,Maven總是基于坐标使用本地倉庫的依賴檔案。

預設情況下,不論是Windows還是Linux,本地倉庫的路徑都為~/.m2/repository(~ 是使用者目錄)

更改本地倉庫路徑:~/.m2/settings.xml,設定localRepository元素的值。

如:

<settings>
    ...
    <localRepository>D:\java\repository</localRepository>
    ...
</settings>
           

安裝構件到本地倉庫:

1)mvn clean install:建構項目輸出檔案并安裝到本地倉庫

2)mvn install:install-file -Dfile=x -DgroupId=x -DartifactId=x -Dversion=x -Dpackaging=x

Dfile待安裝建構路徑;DgroupId、DartifactId、Dversion、Dpackaging聲明其在倉庫中的坐标

2 遠端倉庫

安裝好Maven後,如果不執行任何Maven指令,本地倉庫目錄是不存在的。當使用者輸入第一條Maven指令之後,Maven才會建立本地倉庫,然後根據配置和需要,從遠端倉庫下載下傳構件至本地倉庫。

Maven本地倉庫隻有一個,但可以配置多個遠端倉庫。

好比本地倉庫是書房,遠端倉庫是書店,當使用者需要看一本書時,如果在書房中沒找到,就到書店購買并放回書房。通常一個人隻有一個書房,但外面的書店有很多。

3 中央倉庫

由于原始的本地倉庫是空,Maven必須知道至少一個可用的遠端倉庫,才能在執行Maven指令時下載下傳到需要的構件。

中央倉庫就是這樣一個預設遠端倉庫。在Maven安裝檔案中自帶了中央倉庫的配置。

在Maven安裝目錄/lib/maven-model-builder-xx.jar中通路路徑org/apache/maven/model/pom-4.0.0.xml。

Ps(個人了解):pom-4.0.0.xml 與 pom.xml中<modelVersion>4.0.0</modelVersion> 應該存在某些關聯

pom-4.0.0.xml是所有Maven項目都會繼承的超級POM,檢視該檔案,可以找到中央倉庫配置。

<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>
           

4 私服

私服是一種特殊的遠端倉庫,它是架設在區域網路内的倉庫服務。私服代理廣域網上的遠端倉庫,供區域網路内的Maven使用者使用。

《Maven實戰》閱讀總結(二)Maven倉庫

上圖展示了組織内部使用私服的情況,即使在一台直接連入Internet的個人機器上使用Maven,也應本地建立私服。

建立私服的優點:

節省自己的外網帶寬 消除對外的重複構件下載下傳,降低外網帶寬的壓力。
加速Maven建構 不停的請求外部倉庫十分耗時,Maven的一些内部機制(如快照更新檢查)要求Maven在執行建構時不停地檢查遠端倉庫資料,當項目配置很多外部遠端倉庫時,建構速度大大降低。使用私服,Maven隻需檢查區域網路内私服資料,提高建構速度。
部署第三方建構 安裝組織内部生成的私有構件到私服,供内部Maven使用者
提高穩定性,增強控制 Maven建構高度依賴于遠端倉庫,Internet不穩定,Maven建構也會變得不穩定,甚至失敗,使用私服後,即使暫時沒有Internet,由于私服緩存了很多構件,Maven也能正常運作。此外,很多私服(如Nexus)軟體還提供了額外的功能,如權限管理,RELEASE/SNAPSHOT區分等
降低中央倉庫的負荷 使用私服可以避免很多對中央倉庫的重複下載下傳。

遠端倉庫的配置

在POM中配置遠端倉庫

<repositories>
    <repository>
        <id>...</id>    <!-- 倉庫唯一辨別,重複會覆寫上一個遠端倉庫 -->
        <name>...</name>    <!-- 倉庫名稱 -->
        <url>...</url>    <!-- 倉庫位址 -->
        <releases>    <!-- 重要!控制Maven對于釋出版本構件的下載下傳 -->
            <enabled>...</enabled>    <!-- true/false 控制釋出版本構件的下載下傳 -->
            <updatePolicy>...</updatePolicy>    <!-- 更新政策 daily(預設,每天一次)、never(從不)、always(每次建構)、interval:X(間隔X分鐘) -->
            <checksumPolicy>...</checksumPolicy>    <!-- 檢查檢驗和檔案的政策 warn(預設,校驗失敗,輸出警告資訊)、fail(校驗失敗,無法完成建構)、ignore(忽略校驗失敗) -->
        </releases>
        <snapshots>    <!-- 重要!控制Maven對于快照版本構件的下載下傳 -->
            <enabled>...</enabled>    <!-- true/false 控制快照版本構件的下載下傳 -->
            <updatePolicy>...</updatePolicy>    <!-- 更新政策 daily(預設,每天一次)、never(從不)、always(每次建構)、interval:X(間隔X分鐘) -->
            <checksumPolicy>...</checksumPolicy>    <!-- 檢查檢驗和檔案的政策 warn(預設,校驗失敗,輸出警告資訊)、fail(校驗失敗,無法完成建構)、ignore(忽略校驗失敗) -->
        </snapshots>
        <layout>default</layout>    <!-- 倉庫布局方式 -->
    </repository>
    ...
</repositories>
           

1 遠端倉庫的認證

大部分遠端倉庫無須認證就可通路,但有時出于安全方面考慮,我們需要提供認證資訊才能通路一些遠端倉庫。

配置認證資訊必須配置在settings.xml中,因為POM往往送出到代碼倉庫中供所有成員通路,顯然,本地settings.xml更安全

<settings>
    ...
    <servers>
        <server>
            <id>..</id>    <!-- 需要提供認證資訊才能通路的遠端倉庫ID -->
            <username>...</username>    <!-- 使用者名 -->
            <password>...</password>    <!-- 密碼 -->
        </server>
    </servers>
    ...
</settings>
           

2 部署至遠端倉庫

1) 編輯項目的pom.xml

<project>
    <distributionManagement>
        <repository>    <!-- 指定釋出版本構件的倉庫 -->
            <id>...</id>
            <name>...</name>
            <url>...</url>
        </repository>
        <snapshotRepository>    <!-- 指定快照版本構件的倉庫 -->
             <id>...</id>
            <name>...</name>
            <url>...</url>
        </snapshotRepository>
    </distyibutionManagement>
</project>
           

2) 往遠端倉庫部署構件時,往往需要認證。在settings.xml中配置認證資訊

3)執行mvn clean deploy,部署到遠端倉庫

快照版本

在Maven世界中。任何一個項目或者構件都必須有自己的版本,而Maven又将版本分為兩種:

釋出版本:穩定,格式如:1.0.0、1.3-alpha-4、2.0

快照版本:不穩定,格式如:2.1-SNAPSHOT、2.1-20091214.221414-13

假設:同時開發項目A、B,而項目B依賴于項目A,在項目未正式方布時,開發方案如下

方案一:檢出項目A源碼進行建構。能獲得項目A最新構件,但需要額外的建構操作,而且建構出問題也不好解決,低效

方案二:重複部署項目A,版本号不變。需要清理本地倉庫相同版本号的項目A構件,不然無法下載下傳A最新構件

方案三:不停更新版本。需要頻繁修改POM檔案,同時造成版本号的濫用。

方案四:将項目A的版本設定為快照版本。

Maven在釋出項目快照版本時,會自動打上時間戳。如2.1-20091214.221414-13 表示 2009年12月14日22時14分14秒 第13次快照。通過時間戳,Maven就能找到該構件的最新快照版本。

預設情況下,Maven會每天檢查一次更新(由倉庫配置的updatePolicy控制),也可通過-U指令強制更新,如mvn clean install -U

從倉庫解析依賴的機制

當本地倉庫沒有依賴構件時,Maven會自動從遠端倉庫下載下傳;當依賴版本為快照版本時,Maven會自動找到最新的快照。其依賴解析機制如下

1)依賴範圍是system,Maven直接從本地檔案系統解析構件。

2)根據依賴坐标計算倉庫路徑,Maven直接從本地倉庫尋找構件,如果發現相應構件,則解析成功。

3)本地倉庫不存在,且依賴版本是顯式的釋出版本構件(1.0,1.2-beta-1),周遊所有遠端倉庫,發現後下載下傳并解析使用

4)如果依賴版本是RELEASE和LATEST,則基于更新政策讀取所有遠端倉庫的中繼資料groupId/artifactId/maven-metadata.xml,将其與本地倉庫的對應中繼資料合并後,計算出RELEASE或LATEST的真實的值,然後基于這個值檢查本地和遠端倉庫。

5)如果依賴版本是SNAPSHOT,則基于更新政策讀取所有遠端倉庫的中繼資料groupId/artifactId/version/maven-metadata.xml,将其與本地倉庫的對應中繼資料合并後,得到最新快照版本的值,然後基于該值檢查本地倉庫和遠端倉庫。

6)如果最後解析得到的構件版本是時間戳格式的快照,如1.4.1-20091104.121450-121,則複制其時間戳格式檔案至非時間戳格式,如SNAPSHOT,并使用該非時間戳格式的構件。

Maven基于更新政策來檢查更新,與遠端倉庫配置中<release>和<snapshot>中的子元素<enable>、<updatePolicy>有關,隻有enable為true,才能通路該倉庫對應釋出版本/快照版本的構件資訊,并基于updatePolicy更新政策檢查更新,使用-U可以強制更新。

當Maven檢查完更新政策,并決定檢查依賴版本,就需要檢查倉庫中繼資料maven-metadata.xml

基于groupId和artifactId的maven-metadata.xml

<?xml version="1.0" encoding="UTF-8"?>
<metadata>
  <groupId>org.sonatype.nexus</groupId>
  <artifactId>nexus</artifactId>
  <versioning>
    <latest>1.4.2-SNAPSHOT</latest>    <!-- 指向最新版本 -->
    <release>1.4.0</release>    <!-- 指向最新釋出版本 -->
    <versions>    <!-- 版本曆史記錄 -->
      <version>1.3.5</version>
      <version>1.3.6</version>
      <version>1.4.0-SNAPSHOT</version>
      <version>1.4.0.1-SNAPSHOT</version>
      <version>1.4.1-SNAPSHOT</version>
      <version>1.4.2-SNAPSHOT</version>
    </versions>
    <lastUpdated>20091214221557</lastUpdated>    <!-- 記錄最近更新時間 -->
  </versioning>
</metadata>
           

該XML檔案列出倉庫中存在的該構件的所有可用的版本,Maven通過合并多個遠端倉庫及本地倉庫的中繼資料,就能計算出基于所有倉庫的latest和release分别是什麼,然後再解析具體的構件。

Ps:不推薦依賴聲明中使用LATEST和RELEASE,Maven随機解析到不同的構件,當構件發生變化,可能會造成項目建構失敗,且不易排查。

當依賴版本是快照版本時,Maven也需要檢查更新。

基于groupId、artifactId和version的maven-metadata.xml

<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
  <groupId>org.sonatype.nexus</groupId>
  <artifactId>nexus</artifactId>
  <version>1.4.2-SNAPSHOT</version>
  <versioning>
    <snapshot>
      <timestamp>20091214.221414</timestamp>
      <buildNumber>13</buildNumber>
    </snapshot>
    <lastUpdated>20091214221414</lastUpdated>
  </versioning>
</metadata>
           

該XML檔案的snapshot元素包含timestamp和buildNumber兩個元素分别代表這一快照的時間戳和建構号。并由此可以得到該倉庫中此快照的最新構件版本實際為1.4.2-20091214.221414-13,通過合并所有遠端倉庫和本地倉庫的中繼資料,就能知道所有倉庫中該構件的最新快照。

最後,中繼資料并非永遠正确,當某些構件無法解析,或解析錯誤時,需手工或使用工具(如Nexus)對齊進行修複。

鏡像

如果倉庫X可以提供倉庫Y存儲的所有内容,那麼就可以認定X是Y的一個鏡像。

舉個例子,http://maven.net.cn/content/g...://repol.maven.org/maven2在中國的鏡像,由于地理位置因素,使用該鏡像往往能夠提供比中央倉庫更快的服務。

編輯settings.xml,配置鏡像

<settings>
    ...
    <mirrors>
        <mirror>
            <id>...</id>    <!-- 鏡像倉庫id -->
            <name>...</name>    <!-- 鏡像倉庫名稱 -->
            <url>...</url>    <!-- 鏡像倉庫位址 -->
            <mirrorOf>...</mirrorOf>    <!-- 被鏡像倉庫表達式: *(比對所有遠端倉庫) -->
        </mirror>
    </mirrors>
    ...
</settings>
           

mirrorOf元素用來比對被鏡像倉庫(有點類似于Servlet的url-pattern表達式),當你要通路的遠端倉庫id滿足mirrorOf表示式時,就會被攔截通路鏡像伺服器。表達式文法如下:

* 比對所有遠端倉庫
external:* 比對所有遠端倉庫,localhost除外
a,b 比對a和b倉庫,多個倉庫用,隔開
*,!a 比對所有遠端倉庫,a除外,使用感歎号将倉庫從比對中排除

倉庫搜尋服務

使用Maven進行日常開發時,擷取依賴需要确切的依賴坐标,通過倉庫搜尋服務可以根據關鍵字得到Maven坐标。

Sonatype Nexus http://repository.sonatype.org 提供關鍵字搜尋、類名搜尋、坐标搜尋、校驗和搜尋等功能,坐标和構件下載下傳
aliyun Nexus http://maven.aliyun.com 同上,aliyun架設的公共Nexus倉庫執行個體,服務較快
Jarvana http://www.jarvana.com/jarvana 提供基于關鍵字、類型搜尋,坐标,構件下載下傳。還支援浏覽構件内部内容和便捷的Java文檔浏覽功能
MVNbrowser http://www.mvnbrowser.com 隻提供關鍵字搜尋,坐标,還可檢視構件依賴于那些構件(Dependencies)以及該構件被哪些其他構件依賴(Referenced By)
MVNrepository http://mvnrepository.com 提供關鍵字搜尋,坐标,構件下載下傳,依賴于被依賴關系資訊,構件所含資訊,還能提供一個簡單圖表,顯示某個構件各版本間的大小變化