Maven座標和依賴是任何一個構件在Maven世界中的邏輯表示方式;而構件的物理表示方式是文件,Maven通過倉庫來統一管理這些文件。
Maven倉庫
在Maven的世界中,任何一個依賴、插件或者項目構建的輸出,都可以稱爲一個構件。如項目依賴log4j-1.2.15.jar是一個構件,插件maven-compiler-plugin-2.0.3.jar是一個構件,我們自己的Maven項目構建完成後的輸出.jar/war文件也是一個構件。任何一個構件都有一組座標唯一標識。在我們項目開發中,往往可能會涉及到十幾個甚至幾十個Maven項目,可能大部分項目都需要log4j來打印日誌,那麼是否我們需要在每一個Maven項目中buildpath一份log4j的java類庫呢?答案顯然不是,本着重用性的原則,我們最好把這個java類庫放在一個地方,所有要用到log4j的Maven項目都共用一份log4j java類庫,那麼這個地方就是Maven倉庫。爲了實現重用,項目構架完畢後生成的構件也可以安裝或者部署到Maven倉庫中供其他Maven項目使用。
倉庫佈局
任何一個構件都有其唯一座標,根據這個座標可以定義其在倉庫中的唯一存儲路徑,這便是Maven的倉庫佈局方式。例如log4j:log4j:1.2.15這一依賴,那麼其對應的倉庫路徑爲log4j/log4j/1.2.15/log4j-1.2.15.jar,改路徑與pom對應的座標關係爲groupId/artifactId/version/artifactId-version.packaging。
倉庫的分類
對於Maven來說,倉庫只分爲兩類:本地倉庫和遠程倉庫。當Maven根據座標尋找構件的時候,它會首先查看本地倉庫,如果本地倉庫存在構件,則直接使用;如果本地倉庫不存在此構件,或者需要查看是否有更新的構件版本,Maven就會去遠程倉庫查找,發現需要的構件之後,下載到本地倉庫再使用。如果本地倉庫和遠程倉庫都沒有需要的構件,Maven就會報錯。
中央倉庫是Maven核心自帶的遠程倉庫,它包含了絕大部分開源的構件。在默認配置下,當本地沒有找到Maven需要的構件的時候,它就會自動嘗試從中央倉庫下載。
私服是另一種特殊的遠程倉庫,稍有規模的企業都會在局域網內搭建這樣一個私服,用其代理所有外部的遠程倉庫,不僅速度更快,而且內部項目還能部署到私服上供其他項目使用。
其他公開的遠程倉庫,常見有Java.net.Maven庫和JBoss Mavn庫。
本地倉庫
一般來說,在Maven項目目錄下沒有諸如lib/這樣用來存放依賴文件的目錄。當Maven執行編譯或測試時,如果需要使用依賴文件,它總是基於座標使用本地倉庫的依賴文件。
默認情況下,每個Maven用戶在自己的用戶目錄下都有一個路徑名爲.m2/repository/的倉庫目錄,一般在C盤的用戶目錄下。實際上.m/目錄下還有一個setting.xml文件(一般使用IDE Maven插件的朋友會發現,setting.xml文件已經自動複製過來了,如果沒有,我們可以手動從Maven的安裝目錄下的conf文件夾下複製setting.xml到.m/目錄下)。Repository目錄裏放置的就是本地需要的所有構件。由於系統盤磁盤大小有限,而一個.m2文件隨便可以達到幾個G甚至十幾個G,所以我們有強烈的願望,希望能把本地倉庫搬家,這個倒也不難,只需要在setting.xml文件修改一下如下配置即可:
<localRepository>e:/MavenRepository</localRepository>
這個即爲本地倉庫的地址。
Maven安裝好後,如果不執行任何Maven命令,本地倉庫目錄是不存在的。當用戶輸入第一條Maven命令之後,Maven纔會創建本地倉庫,然後根據配置和需要,從遠程倉庫下載構件至本地倉庫。
中央倉庫
由於最原始的本地倉庫是空的,Maven必須知道至少一個可用的遠程倉庫,才能在執行Maven命令的時候下載到需要的構件。中央倉庫就是這樣一個默認的遠程倉庫,Maven安裝文件自帶了中央倉庫的配置。我們可以打開Maven的安裝目錄,在lib/下找到maven-model-builder.jar(每個人版本可能不一樣),然後利用反編譯工具,可以找到org/apache/maven/model/pom-4.0.0.xml文件,可以看到如下配置:
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>http://repo.maven.apache.org/maven2</url>
<layout>default</layout>//默認倉庫佈局方式
<snapshots>//快照版本
<enabled>false</enabled>//不從中央倉庫下載快照版本的構件
</snapshots>
</repository>
</repositories>
私服
私服是一種特殊的遠程倉庫,它是架設在局域網內的倉庫服務,當Maven需要下載構件的時候,它從私服請求,如果私服上不存在該構件,則從外部遠程倉庫下載,緩存在私服上之後,再爲Maven的下載提供服務。
私服強大之處在於:
1、能節省自己的外網寬帶。
2、加速Maven構建。不停地連接外部倉庫是十分耗時的,但是Maven的一些內部機制(如快照更新檢查)要求Maven在執行構建的時候不停地檢查遠程倉庫數據。因此,當項目配置了很多外部遠程倉庫的時候,構建的速度會被大大降低。使用私服可以很好地解決這個問題。
3、部署第三方構建。
當某個構件無法從任何一個外部遠程倉庫獲得,怎麼辦?很典型的例子是,JDBC驅動由於版權因素不能發佈到公共倉庫中。建立私服後,便可以將這些構件部署到這個內部倉庫中,供內部的Maven項目使用。
4、安全性。從兩點上得到保障,一是及時暫時沒有Internet連接,由於私服中已經緩存了大量構件,Maven仍能正常運行;二是有些私服還提供權限管理、倉庫分區等服務;
5、降低中央倉庫的負荷,如果沒有私服,每個人使用Maven都從中央倉庫下載,中央倉庫承受的壓力,下載的速度可想而知。
遠程倉庫的配置
很多情況下,默認中央倉庫無法滿足項目的需求,可能項目需要的構件存在另外一個遠程倉庫中,如JBOSS Maven倉庫。這時,我們可以在POM如下配置倉庫:
<project>
...
<repositories>
<repository>
<id>jboss</id>
<name>JBoss Repository</name>
<url>http://repository.jboss.com/maven2/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<layout>default</layout>
<repository>
</repositories>
</project>
在repositories元素下,可以使用repository子元素 一個或者多個遠程倉庫。任何一個倉庫聲明的id必須是唯一的,該配置中的url指向了倉庫的地址,一般採用http協議,releases元素的enabled的值爲true,snapshots元素的enabled的值爲false,則說明,只會下載遠程倉庫發佈版本的構件而不會下載快照版本的構件。對於releases和snapshots,它們還包含了另外兩個元素updatePolicy和checkSumPolicy。
<releases>
<updatePolicy>daily</ updatePolicy>
<enabled>true</enabled>
<checkSumPolicy>ignore</checkSumPolicy>
</releases>
updatePolicy爲從Jboss倉庫檢查的頻率,值可以爲daily(每天)、never(從不)、always(每次構建都檢查)、Interval(每隔多少分鐘檢查一次)。
checkSumPolicy用來配置Maven檢查檢驗和文件的策略,當構件被部署到Maven倉庫時,會同時部署對應的檢驗和文件。在下載構件的時候,Maven會驗證檢驗和文件。如果驗證檢驗失敗,當checkSumPolicy爲warn時,Maven會在執行構件時輸出警告信息,其他可用的值有:fail當驗證檢驗失敗,就讓Maven構建失敗;ignore完全忽略校驗和失誤。
遠程倉庫的驗證
大部分倉庫都無需認證就可以訪問,但有時處於安全方面的考慮,我們需要提供認證信息才能訪問遠程倉庫。爲了防止非法的倉庫訪問,管理員往往會提供一組用戶名和密碼,這時,爲了能訪問倉庫,就需要在setting.xml文件中配置:
<settings>
...
<servers>
<server>
<id>
my-proj
</id>
<username>
repo-user
</username>
<password>
repo-password
</password>
</server>
</servers>
</settings>
setting文件中的server的id必須與pom文件的需要認證的repository元素的id一致,正是此id將認證信息和倉庫配置聯繫在了一起。
將構件部署至遠程倉庫
編輯項目pom.xml文件
<project>
...
<distributionManagement>
<repository>
<id>proj-releases</id>
<name>proj releases repository</name>
<url>http://192.168.2.11:1521/proj-releases/</url>
</repository>
<snapshotRepository>
<id>proj-snapshots</id>
<name>proj snapshots repository</name>
<url>http://192.168.2.11:1521/projsnapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
往遠程倉庫部署構件的時候,往往需要認證。簡而言之,就是需要在setting文件中配置server元素,其id與倉庫的id匹配,並配置正確的認證信息。
鏡像
如果倉庫x可以提供倉庫y存儲的所有內容,那我們可以說x是y的鏡像,典型的事例是,很多國外的服務在中國都有中國的鏡像,這樣的目的是能夠提供更快的服務。
<settings>
...
<mirrors>
<mirror>
<id>maven.net.cn</id>
<name>one of the central mirror in China</name>
<url>http://maven.net.cn/content/groups/public</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>
以上就是配置的就是中央倉庫在中國的鏡像。
鏡像更爲常見的是結合私服的使用,由於私服可以代理任何外部的公共倉庫,因此,對於組織內部的Maven用戶來說,使用一個私服地址,就相當於使用了所有需要的外部倉庫,這可以將配置集中到私服,從而簡化Maven本身的配置,在這種情況下,任何需要的構件都可以從私服獲得,私服就是所有倉庫的鏡像,這時可以如此配置:
<settings>
...
<mirrors>
<mirror>
<id>internal repository</id>
<name>internal repository manager</name>
<url>http://192.168.2.11:1521/maven2/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
</settings>
mirrorOf元素的值爲*代表該配置是所有倉庫的鏡像,任何對於遠程倉庫的請求都會被轉至http://192.168.2.11:1521/maven2/。
Maven還支持其他高級的鏡像配置:
<mirrorOf>*</mirrorOf>
<mirrorOf>external:*</mirrorOf>匹配所有不在本機上的遠程倉庫
<mirrorOf> repo1,repo2</mirrorOf>匹配倉庫repo1,repo2
<mirrorOf> *,!repo2</mirrorOf>匹配所有倉庫,repo2除外
需要注意的是,由於鏡像倉庫完全屏蔽掉被鏡像倉庫,當鏡像倉庫不穩定或者停止服務的時候, Maven仍將無法訪問被鏡像倉庫,因而無法下載構件。