參考來源:
https://www.liupeng.mobi/archives/1816 (包含有依賴下載過程詳解)
https://blog.csdn.net/chenpuzhen/article/details/84201811
https://blog.csdn.net/pinebud55/article/details/78667299
https://www.cnblogs.com/songcuiting/p/8783750.html
一、Maven中坐標概念
Maven對依賴進行統一管理,通過定義項目的依賴關系,Maven從倉庫查找和下載依賴的組件(jar包、war包、pom文件等等)。那么Maven如何來唯一標識一個依賴組件呢?這就涉及到Maven中坐標的概念。
Maven中的坐標包含:groupId 、artifactId、version 三個元素:
- groupId:項目所在組,一般是組織或公司。
- artifactId:是當前項目在組中的唯一ID。
- version:表示版本。Release表示發布版本,SNAPSHOT表示快照,表示此項目還在開發中,不穩定。
Maven在定義依賴時,需要指定如上的坐標。如:以pom.xml中的junit為例:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
通過如上依賴組件的坐標定義,Maven從倉庫中按照 “groupId”\“artifactId”\"version" 的路徑來下載依賴組件包。
二、通過greoupId和ArtifactId唯一定位到一個項目,但是項目過程中伴隨着多次編譯和發布,Maven中是如何管理version的?
詳細的關於Maven中版本管理的細節,見對應章節。此處僅做大概描述,為后續解釋Maven下載依賴組件過程做鋪墊。
Maven中的項目版本分為Release版本和Snapshot版本。
Release版本為發布的穩定版本,可以理解為一個版本號只歸檔、發布一次。版本號一般采用類似1.0、1.1的方式。
Snapshot版本為開發過程中的迭代版本,對於同一版本號,開發過程中可以多次編譯、歸檔。版本號一般采用"版本號-SNAPSHOT"的格式,比如1.0-SNAPSHOT。
三、基於以上坐標、版本機制,我們看看依賴組件在倉庫中是如何歸檔的?
以Mytest項目為例,其在遠程倉庫、本地倉庫歸檔內容可以如下:
1、在遠程倉庫的歸檔(Realse倉庫)
|--1.0.0
|--Mytest-1.0.0.pom
|--Mytest-1.0.0.pom.asc
|--Mytest-1.0.0.jar
|--Mytest-1.0.0.jar.asc
|--1.0.1
|--Mytest-1.0.1.pom
|--Mytest-1.0.1.pom.asc
|--Mytest-1.0.1.jar
|--Mytest-1.0.1.jar.asc
|--maven-metadata.xml
如上,其項目歸檔根目錄下,以版本號為目錄來歸檔不同的release版本。
1)每個release版本下,包含jar項目包、及.pom文件。其中.pom文件記錄的是項目本次版本的pom定義,內含本項目坐標、依賴關系、插件信息、構建過程定義等。
2)項目歸檔根目錄下,還有一個maven-metadata.xml文件,這個文件干啥用呢?
maven-metadata.xml內容樣例如下:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>com.AAAAA</groupId>
<artifactId>Mytest</artifactId>
<version>1.1.</version>
<versioning>
<latest>1.1.1</latest>
<release>1.1.1</release>
<versions>
<version>1.0.0</version>
<version>1.0.1</version>
</versions>
<lastUpdated>20191221041500</lastUpdated>
</versioning>
</metadata>
如上樣例所示,maven-metadata.xml中實際上記錄的是項目的歷史版本過程。
2、在遠程倉庫的歸檔(Snapshot倉庫)
|--1.0.0-SNAPSHOT
|--Mytest-1.0.0-20191215.090030.pom
|--Mytest-1.0.0-20191215.090030.jar
|--Mytest-1.0.0-20191216.160005.pom
|--Mytest-1.0.0-20191216.160005.jar
|--maven-metadata.xml
|--1.0.1-SNAPSHOT
|--Mytest-1.0.1-20191220.100021.pom
|--Mytest-1.0.1-20191220.100021.jar
|--Mytest-1.0.1-20191220.164405.pom
|--Mytest-1.0.1-20191220.164405.jar
|--maven-metadata.xml
|--maven-metadata.xml
如上,其項目歸檔根目錄下,以版本號為目錄來歸檔不同的Snapshot版本。和Release倉庫文件目錄結構的差異如下:
1)版本目錄(如1.0.1-SNAPSHOT目錄)下多了個maven-metadata.xml文件。樣例:
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
<groupId>com.AAAAA</groupId>
<artifactId>Mytest</artifactId>
<version>1.0.1-SNAPSHOT</version>
<versioning>
<snapshot>
<timestamp>20191220.164405</timestamp>
<buildNumber>34</buildNumber>
</snapshot>
<lastUpdated>20191220164405</lastUpdated>
<snapshotVersions>
<snapshotVersion>
<extension>jar</extension>
<value>1.0.1-20191220.100021</value>
<updated>20191220100021</updated>
</snapshotVersion>
<snapshotVersion>
<extension>pom</extension>
<value>1.0.1-20191220.164405</value>
<updated>20191220164405</updated>
</snapshotVersion>
</snapshotVersions>
</versioning>
</metadata>
因為Maven中同一個Snopshot版本是可以多次編譯、歸檔的,所以具體某個Snopshot版本內的mave-matedata.xml記錄了本Snapshot版本的多次歸檔的歷史記錄。本文件中的歷史記錄采用 版本號+時間戳 方式。
2)項目Snapshot倉庫 根目錄 下的maven-matedata.xml樣例如下:
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>com.fyklocal</groupId>
<artifactId>demologinserver</artifactId>
<version>1.0.1-SNAPSHOT</version>
<versioning>
<versions>
<version>1.0.0-SNAPSHOT</version>
<version>1.0.1-SNAPSHOT</version>
</versions>
<lastUpdated>20200123083452</lastUpdated>
</versioning>
</metadata>
項目根目錄下成這個maven-metadata.xml記錄的是本項目SNAPSHOT版本的歷史記錄。
3、項目在本地倉庫中的目錄
|--1.0.0
|--Mytest-1.0.0.pom
|--Mytest-1.0.0.pom.asc
|--Mytest-1.0.0.jar
|--Mytest-1.0.0.jar.asc
|--1.0.0-SNAPSHOT
|--Mytest-1.0.0-SNAPSHOT.pom
|--Mytest-1.0.0-SNAPSHOT.jar
|--maven-metadata-local.xml
|--1.0.1
|--Mytest-1.0.1.pom
|--Mytest-1.0.1.pom.asc
|--Mytest-1.0.1.jar
|--Mytest-1.0.1.jar.asc
|--1.0.1-SNAPSHOT
|--Mytest-1.0.1-SNAPSHOT.pom
|--Mytest-1.0.1-SNAPSHOT.jar
|--maven-metadata-local.xml
|--maven-metadata-local.xml
和遠程倉相比:
1)maven-metadata.xml文件本地命名為meven-metadata-local.xml
2)根目錄的maven-metadata-local.xml中同時記錄了 Release 和 SNOAPSHOT 版本的歷史。
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>com.AAAAA</groupId>
<artifactId>Mytest</artifactId>
<version>1.0.1</version>
<versioning>
<latest>1.0.1</latest>
<release>1.0.1</release>
<versions>
<version>1.0.0-SNAPSHOT</version>
<version>1.0.0</version>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.1</version>
</versions>
<lastUpdated>20191221041500</lastUpdated>
</versioning>
</metadata>
3)SNAPSHOT版本目錄下僅記錄最新一次SNOTSHOT版本信息(未從遠程倉下載,則是本地最后一次mvn install的;從遠程倉下載,則是遠程倉上本SNAPSHOT版本歸檔的最后一次)。
.pom文件和.jar文件由於只保存最新一份,直接以SNAPSHOT命名,不需要以時間戳命名。
如:1.0.1-SNAPSHOT/maven-metadata-local.xml 文件內容如下。和遠程倉相比,版本也直接使用1.0.1-SNAPSHOT,不需要用時間戳命名。
<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
<groupId>com.fyklocal</groupId>
<artifactId>demologinserver</artifactId>
<version>1.0.1-SNAPSHOT</version>
<versioning>
<snapshot>
<localCopy>true</localCopy>
</snapshot>
<lastUpdated>20191220164405</lastUpdated>
<snapshotVersions>
<snapshotVersion>
<extension>jar</extension>
<value>1.0.1-SNAPSHOT</value>
<updated>20191220100021</updated>
</snapshotVersion>
<snapshotVersion>
<extension>pom</extension>
<value>1.0.1-SNAPSHOT</value>
<updated>20191220164405</updated>
</snapshotVersion>
</snapshotVersions>
</versioning>
</metadata>
總結:
1).pom文件是對應每個版本包一份,用於記錄當前版本包的POM信息。
2)maven-metadata.xml用於記錄項目構建歷史記錄。下載依賴組件使,用於做版本和時間比較。
四、那么Maven從中央倉庫、遠程倉庫下載依賴組件時,到底是如何根據版本工作的呢?
閱讀本章節前,請先閱讀本文前面部分關於遠程倉庫、本地倉庫maven-metadata.xml、.pom文件的說明。
如第(一)章節所說,Maven中依賴通過groupId 、artifactId、version 三個元素組成的坐標定位,在pom.xml定義的依賴也包含這三個元素。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
在執行mvn命令時,會根據pom.xml的定義解析依賴,並下載。
(1)當指定的依賴組件版本 為 具體某個Release版本(如:2.1、2.1.1等)
Maven會現在本地倉庫中根據 {groupId}/{artifactId} 路徑來查找對應版本的組件是否存在?
■ 如果本地倉庫存在,直接使用。
■ 如果本地倉庫不存在,則先從中央倉庫按照 {groupId}/{artifactId}/maven-metadata.xml 查找是否存在對應版本的組件。如果存在:
(A)合並中央倉庫/遠程倉庫中 groupId/artifactId/ 下的maven-metadata.xml到本地倉庫的{groupId}/{artifactId}/maven-metadata-local.xml中。
(B)並下載 {groupId}/{artifactId}/{version}下的組件到本地倉庫。
■ 如果中央倉庫也不存在,逐個查找支持Release版本的遠程倉庫,先檢查遠程倉庫的 <updatePolicy>配置的更新頻率是否達到,如果更新次數沒達到,則繼續同中央倉庫的(A)、(B)步驟。
(2)當指定的依賴組件版本 為 “RELEASE” (表示獲取最新的Release版本。不推薦)
Maven會檢查中央倉庫,及所有支持Release版本的遠程倉庫、檢查<updatePolicy>配置的更新頻率是否達到。對於所有滿足下載條件的倉庫:
■ 從中央倉庫、所有遠程倉庫中 下載 {groupId}/{artifactId}/maven-metadata.xml到本地倉庫,並和本地倉庫{groupId}/{artifactId}/maven-metadata-local.xml合並。合並后,得到最新Release版本的值。
■ 如果本地倉庫中的 組件 就是最新版本,則直接使用。
■ 如果本地倉庫中的 組件 不是最新版本,則根據最新版本號,從 中央倉庫/遠程倉庫 下載組件到本地倉庫。
(3)當指定的依賴組件版本 為 具體某個SNAPSHOT版本(如:2.1-SNAPSHOT等)
Maven會檢查所有支持Snapshot版本的遠程倉庫,檢查<updatePolicy>配置的更新頻率是否達到。對於更新次數沒達到所有遠程倉庫:
■ 從所有遠程倉庫中 下載 {groupId}/{artifactId}/2.1-SNAPSHOT/maven-metadata.xml到本地倉庫,並和本地倉庫maven-metadata-local.xml合並,根據SNAPSHOT的時間戳版本號,獲取2.1-SNAPSHOT對應版最新一次信息。(SNAPSHOT同一版本,可以構建歸檔多次,通過時間說格式的版本號區分,如:Mytest-1.0.1-20191220.100021.jar。)
■ 下載2.1-SNAPSHOT版本對應的最新組件到本地倉庫的 {groupId}/{artifactId}/2.1-SNAPSHOT/目錄下,並把2.1-SNAPSHOT的時間戳版本 變更 為-SNAPSHOT版本(如:Mytest-1.0.1-20191220.100021.jar 變更為 Mytest-1.0.1-SNAPSHOT.jar)。
■ 更新本地倉庫{groupId}/{artifactId}/maven-metadata-local.xml、{groupId}/{artifactId}/2.1-SNAPSHOT/maven-metadata-local.xml中對應的時間戳等信息。
(4)當指定的依賴組件版本 為 “SNAPSHOT” (表示獲取最新的SNAPSHOT版本)
Maven會檢查所有支持Snapshot版本的遠程倉庫、檢查<updatePolicy>配置的更新頻率是否達到。對於所有滿足下載條件的倉庫:
■ 從所有遠程倉庫中 下載 {groupId}/{artifactId}/maven-metadata.xml到本地倉庫,並和本地倉庫{groupId}/{artifactId}/maven-metadata-local.xml合並。合並后,得到最新Snapshot版本號。
■ 同(3)中步驟,根據最新的Snapshot版本號,獲取此Snapshot版本號最新一次歸檔的組件。
