在Maven世界中,依賴缚去、插件潮秘、項(xiàng)目構(gòu)建完成后輸出的jar包都可以看作是一個構(gòu)件,任何一個構(gòu)件都有一組坐標(biāo)唯一標(biāo)識易结。Maven實(shí)現(xiàn)了重用枕荞,得益于坐標(biāo)機(jī)制。Maven在倉庫中存儲所有Maven項(xiàng)目共享的構(gòu)件搞动。我們的項(xiàng)目構(gòu)建完畢后生成的構(gòu)件也可以安裝或者部署到倉庫中躏精,供其他項(xiàng)目使用。
倉庫的布局
任何一個構(gòu)件都有其唯一的坐標(biāo)鹦肿,根據(jù)這個坐標(biāo)可以定義其在倉庫中的唯一存儲路徑矗烛,路徑與坐標(biāo)大致對應(yīng)關(guān)系為 groupId/artifactId/version/artifactId-version.packaging
我們來看一下Maven處理倉庫布局的源碼:
private static final char PATH_SEPARATOR = '/';
private static final char GROUP_SEPARATOR = '.';
private static final char ARTIFACT_SEPARATOR = '-';
public String pathOf( Artifact artifact ){
ArtifactHandler artifactHandler = artifact.getArtifactHandler();
StringBuilder path = new StringBuilder( 128 );
path.append( formatAsDirectory( artifact.getGroupId() ) ).append( PATH_SEPARATOR );
path.append( artifact.getArtifactId() ).append( PATH_SEPARATOR );
path.append( artifact.getBaseVersion() ).append( PATH_SEPARATOR );
path.append( artifact.getArtifactId() ).append( ARTIFACT_SEPARATOR ).append( artifact.getVersion() );
if ( artifact.hasClassifier() ){
path.append( ARTIFACT_SEPARATOR ).append( artifact.getClassifier() );
}
if ( artifactHandler.getExtension() != null && artifactHandler.getExtension().length() > 0 ){
path.append( GROUP_SEPARATOR ).append( artifactHandler.getExtension() );
}
return path.toString();
}
private String formatAsDirectory( String directory ){
return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR );
}
依然用之前的POM來看一下
<groupId>com.play.myMaven</groupId>
<artifactId>hello-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
- 基于構(gòu)件的groupId準(zhǔn)備路徑:formatDirectory()將groupId中的'.'分隔符轉(zhuǎn)換為'/'分隔符。groupId: com.play.myMaven會被轉(zhuǎn)化為com/play/myMaven箩溃,然后append一個'/'瞭吃,即com/play/myMaven/。
- 基于構(gòu)件的artifactId準(zhǔn)備路徑:直接在artifactId后添加'/'涣旨。artifactId:hello-maven畔况,即com/play/myMaven/hello-maven/适荣。
- 版本信息:也是直接在版本信息后添加'/',即com/play/myMaven/hello-maven/1.0-SNAPSHOT/。值得注意的是冈敛,這里用到的artifactId.getBaseVersion(),是為SNAPSHOT版本服務(wù)的,比如1.0-SNAPSHOT,getBaseVersion為1.0(但是按照目前自己打包好的結(jié)果顯示依然為1.0-SNAPSHOT导俘,在此先標(biāo)注一下)。
- 最后加上artifactId-version剔蹋,即com/play/myMaven/hello-maven/1.0-SNAPSHOT/hello-maven-1.0-SNAPSHOT旅薄。
- 存在classifier時,添加-classifier泣崩。
-
檢查構(gòu)件的extension少梁,存在即添加.extension〗酶叮可以看到extension是從artifactIdHandler中獲取凯沪,artifactIdHandler是由項(xiàng)目的packaging決定的,即.packaging买优,所以我們的路徑為com/play/myMaven/hello-maven/1.0-SNAPSHOT/hello-maven-1.0-SNAPSHOT.jar
倉庫分類
本地倉庫和遠(yuǎn)程倉庫妨马。Maven會根據(jù)構(gòu)件坐標(biāo)信息優(yōu)先查看本地倉庫,如果本地倉庫存在此構(gòu)件杀赢,直接使用烘跺,如果不存在,或者需要查看是否有更新的構(gòu)件版本脂崔,Maven會去遠(yuǎn)程倉庫查找滤淳,找到了即下載到本地倉庫再使用。若本地和遠(yuǎn)程倉庫均無此構(gòu)件砌左,Maven會報(bào)錯脖咐。
中央倉庫是Maven默認(rèn)內(nèi)置的遠(yuǎn)程倉庫。
私服是另一種特殊的遠(yuǎn)程倉庫绊困,為了節(jié)省帶寬和時間文搂,應(yīng)該在局域網(wǎng)內(nèi)假設(shè)一個私有的倉庫服務(wù)器,用來代理所有外部的遠(yuǎn)程倉庫秤朗。內(nèi)部項(xiàng)目還能夠部署到私服上供其他項(xiàng)目使用。
遠(yuǎn)程倉庫除了中央倉庫和私服還有其他公開的遠(yuǎn)程倉庫笔喉,例如Java.net Maven庫和JBoss庫
1.本地倉庫
默認(rèn)情況下取视,無論是Windows還是Linux,每個用戶在自己的用戶目錄下都有一個路徑為.m2/repository的倉庫目錄常挚,我的Windowsvebdu倉庫地址為C:\Users\songyanyan.m2\repository作谭。在Linux中以 . 開頭的文件/目錄默認(rèn)隱藏,使用ls -a顯示奄毡。
當(dāng)然折欠,我們也可以自定義本地倉庫目錄地址。編輯文件~/.m2/repository/settings.xml,修改localRepository元素值锐秦。
<!-- localRepository
| The path to the local repository maven will use to store artifacts.
| Default: ~/.m2/repository
<localRepository>/path/to/local/repo</localRepository> -->
<localRepository>D:/Repository/m2repo</localRepository>
默認(rèn)情況下咪奖,~/.m2/repository/settings.xml文件不存在,我們需要從Maven安裝目錄$M2_HOME復(fù)制出來一份$M2_HOME/conf/settings.xml文件酱床。不建議直接修改全局目錄的settings.xml文件羊赵,因?yàn)檫@個文件是全局范圍的,整臺機(jī)器上的所有用戶都會直接受到該配置的影響 對復(fù)制到用戶目錄~/.m2/repository/settings.xml文件進(jìn)行修改即可扇谣。
本地倉庫的構(gòu)件組成
- Maven從遠(yuǎn)程倉庫下載到本地倉庫
- 本地項(xiàng)目的構(gòu)件安裝到本地倉庫中(mvn clean install)
2.遠(yuǎn)程倉庫
安裝好Maven后不執(zhí)行任何Maven命令昧捷,本地倉庫目錄是不存在的。當(dāng)輸入第一條Maven命令之后罐寨,Maven才會創(chuàng)建本地倉庫靡挥,并根據(jù)配置和需要從遠(yuǎn)程倉庫下載構(gòu)件至本地倉庫。
每個用戶只有一個本地倉庫鸯绿,但可以配置訪問很多遠(yuǎn)程倉庫跋破。
3.中央倉庫
https://repo.maven.apache.org/maven2 默認(rèn)的遠(yuǎn)程倉庫。
我們來解壓一下$M2_HOME/lib/maven-model-builder-3.3.9.jar楞慈,進(jìn)入\org\apache\maven\model\幔烛,打開pom-4.0.0.xml,這個是所有Maven項(xiàng)目都會繼承的超級POM
<!-- START SNIPPET: superpom -->
<project>
<modelVersion>4.0.0</modelVersion>
<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>
...
<build>
<directory>${project.basedir}/target</directory>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName>
<testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
...
</build>
<reporting>
<outputDirectory>${project.build.directory}/site</outputDirectory>
</reporting>
...
</project>
<!-- END SNIPPET: superpom -->
- id:central囊蓝,是對中央倉庫進(jìn)行唯一標(biāo)識
- name:Central Repository饿悬,名為Central Repository中央倉庫
- url:https://repo.maven.apache.org/maven2 倉庫地址
- layout:default默認(rèn)倉庫布局(即上文中的倉庫布局)
- snapshots:enabled→false表示不從中央倉庫下載快照版本的構(gòu)件。
可以看到包括build元素中定義的目錄結(jié)構(gòu)也同前幾篇講的一致聚霜。項(xiàng)目主代碼目錄和測試代碼目錄也都可以知道是在這個位置進(jìn)行定義的狡恬。
私服
私服是特殊的遠(yuǎn)程倉庫,它是架設(shè)在局域網(wǎng)內(nèi)的倉庫服務(wù)蝎宇,代理廣域網(wǎng)上的遠(yuǎn)程倉庫弟劲,供局域網(wǎng)內(nèi)Maven用戶使用。
當(dāng)Maven需要下載構(gòu)件時候姥芥,它從私服請求兔乞,若私服不存在該構(gòu)件,則從外部的遠(yuǎn)程倉庫下載凉唐,緩存在私服上后庸追,再為Maven的下載請求提供服務(wù)。此外台囱,我們本地也可上傳構(gòu)件到私服供大家使用淡溯。使用私服可以:
- 節(jié)省自己的外網(wǎng)帶寬。
- 加速M(fèi)aven構(gòu)建簿训。
- 部署第三方構(gòu)件咱娶。
- 提高構(gòu)建穩(wěn)定性米间,增強(qiáng)控制。
- 降低中央倉庫的負(fù)荷膘侮。
遠(yuǎn)程倉庫
a.遠(yuǎn)程倉庫的配置
倉庫信息配置在POM文件中屈糊。
在<repositories>元素下可以聲明一個或多個遠(yuǎn)程倉庫<repository>
<!-- Maven倉庫 -->
<repositories>
<repository>
<id>myproj</id>
<name>Myproj Repository</name>
<url>http://172.17.5.244/repository/maven</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
<layout>default</layout>
</repository>
</repositories>
在snapshots和releases元素下,除了enabled喻喳,它們還有另外兩個子元素updatePolicy和checksumPolicy
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</snapshots>
- updatePolicy用來配置Maven從遠(yuǎn)程倉庫檢查更新的頻率另玖。
daily——(默認(rèn)值)每天檢查一次更新
never——從不檢查更新
always——每次構(gòu)建都檢查更新
interval:X——每隔X分鐘檢查一次更新 - checksumPolicy用來配置Maven檢查校驗(yàn)和文件的策略。當(dāng)構(gòu)件被部署到Maven倉庫中時表伦,會同時部署對應(yīng)的校驗(yàn)和文件谦去。下載構(gòu)件時候,Maven會驗(yàn)證校驗(yàn)和文件蹦哼。checksumPolicy值為:
warn——(默認(rèn)值)Maven會在執(zhí)行構(gòu)建時輸出警告信息
fail——Maven遇到校驗(yàn)和錯誤就讓構(gòu)建失敗
ignore——Maven完全忽略校驗(yàn)和錯誤
b.遠(yuǎn)程倉庫的認(rèn)證
出于安全考慮鳄哭,組織內(nèi)有一個Maven倉庫服務(wù)器,該服務(wù)器為每個項(xiàng)目都提供獨(dú)立的Maven倉庫纲熏,為了防止非法的倉庫訪問妆丘,管理員為每個倉庫提供一組用戶名和密碼。為了能讓Maven訪問倉庫內(nèi)容局劲,就需要配置認(rèn)證信息勺拣。
倉庫信息配置在POM中,認(rèn)證信息配置在settings.xml中鱼填。POM往往被提交到代碼倉庫中供所有成員訪問药有,settings一般只放在本機(jī)
<servers>
<server>
<id>myproj</id>
<username>songyanyan</username>
<password>xxx</password>
</server>
<server>
<id>releases</id>
<username>songyanyan</username>
<password>xxx</password>
</server>
<server>
<id>snapshots</id>
<username>songyanyan</username>
<password>xxx</password>
</server>
<servers>
server元素中的id必須與POM中需要認(rèn)證的repository元素的id完全一致。正是這個id將認(rèn)證信息與倉庫配置聯(lián)系在了一起苹丸。
c.部署至遠(yuǎn)程倉庫
部署構(gòu)件到私服愤惰。需要配置distributionManagement元素
<!-- 制品管理 -->
<distributionManagement>
<repository>
<id>releases</id>
<name>Proj Release Repository</name>
<url>http://172.17.5.244/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>snapshots</id>
<name>Proj Snapshot Repository</name>
<url>http://172.17.5.244/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
distributionManagement包含repository和snapshotRepository子元素,前者表示發(fā)布版本構(gòu)件的倉庫赘理,后者表示快照版本的倉庫宦言。配置認(rèn)證方式同上文b.遠(yuǎn)程倉庫的認(rèn)證一致,server元素的id與倉庫id匹配商模。
不論從遠(yuǎn)程倉庫下載構(gòu)件還是部署構(gòu)件至遠(yuǎn)程倉庫奠旺,當(dāng)需要認(rèn)證的時候,配置的方式是一樣的施流。
配置完成凉倚,運(yùn)行mvn clean deploy,Maven會將項(xiàng)目構(gòu)建輸出的構(gòu)件部署到對應(yīng)的遠(yuǎn)程倉庫嫂沉。
從倉庫解析依賴的機(jī)制
本地倉庫沒有該依賴構(gòu)件時,Maven會自動從遠(yuǎn)程倉庫下載扮碧;當(dāng)依賴版本為快照的時候趟章,Maven會自動找到最新的快照杏糙。背后的機(jī)制:
- 依賴的范圍是system時,Maven直接從本地系統(tǒng)解析構(gòu)件蚓土。
- 根據(jù)依賴坐標(biāo)計(jì)算倉庫路徑后宏侍,嘗試直接從本地倉庫尋找構(gòu)件,發(fā)現(xiàn)相應(yīng)構(gòu)件蜀漆,解析成功谅河!
- 解析不成功,如果依賴的版本是顯式的發(fā)布版本構(gòu)件确丢,如1.2绷耍、2.1-beta-1,則遍歷所有遠(yuǎn)程倉庫鲜侥,發(fā)現(xiàn)后下載并解析褂始。
- 如果依賴的版本是REALEASE或LATEST,則依據(jù)更新策略讀取所有遠(yuǎn)程倉庫的元數(shù)據(jù)groupId/artifactId/maven-metadata.xml描函,對應(yīng)本地倉庫元數(shù)據(jù)崎苗,得到最新快照版本值。
<metadata modelVersion="1.1.0">
<groupId>com.play.myMaven</groupId>
<artifactId>hello-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<versioning>
<snapshot>
<localCopy>true</localCopy>
</snapshot>
<lastUpdated>20180606025623</lastUpdated>
<snapshotVersions>
<snapshotVersion>
<extension>jar</extension>
<value>1.0-SNAPSHOT</value>
<updated>20180606025623</updated>
</snapshotVersion>
<snapshotVersion>
<extension>pom</extension>
<value>1.0-SNAPSHOT</value>
<updated>20180606025623</updated>
</snapshotVersion>
</snapshotVersions>
</versioning>
</metadata>
只有倉庫開啟了對于發(fā)布/快照版本的支持(倉庫配置enabled元素)舀寓,才可以訪問該倉庫的發(fā)布版本構(gòu)件信息胆数。我們可以在命令行中加入-U,強(qiáng)行檢查更新互墓。
鏡像
如果倉庫X可以提供倉庫Y存儲的所有內(nèi)容必尼,那么X就可以認(rèn)為是Y的一個鏡像。
我們一般使用國內(nèi)鏡像會好很多轰豆。我們編輯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>
mirrorOf值為central胰伍,即表示該配置為中央倉庫的鏡像也可以配置多鏡像。
鏡像結(jié)合私服酸休,即私服就是所有倉庫的鏡像骂租,我們可以這樣配置:
<mirror>
<id>inter-repo</id>
<url>http://xxx/xxx/</url>
<mirrorOf>*</mirrorOf>
</mirror>
這里的*號表示該配置是所有Maven倉庫的鏡像,對于任何遠(yuǎn)程倉庫的請求都會被轉(zhuǎn)至http://xxx/xxx/斑司。若該鏡像倉庫需要認(rèn)證渗饮,則配置相應(yīng)id為inter-repo的<server>即可。
- <mirrorOf>*</mirrorOf> 匹配所有遠(yuǎn)程倉庫
- <mirrorOf>external:*</mirrorOf> 匹配所有遠(yuǎn)程倉庫宿刮,使用localhost的除外互站,使用file://協(xié)議的除外。即匹配所有不在本機(jī)上的遠(yuǎn)程倉庫僵缺。
- <mirrorOf>repo1,repo2</mirrorOf> 匹配倉庫repo1胡桃,repo1使用逗號分隔。
- <mirrorOf>*,!repo2</mirrorOf>匹配所有遠(yuǎn)程倉庫磕潮,除了repo2
倉庫搜索服務(wù)
Sonatype翠胰,關(guān)鍵字搜索容贝、類名搜索、坐標(biāo)搜索之景、校驗(yàn)和搜索等功能斤富。
注:《Maven實(shí)戰(zhàn)》學(xué)習(xí)筆記