5 Seven 2017
前言
使用 maven 也有一段时间了,有时候在配置 repository,mirror,profile的时候,总会导致 jar 拉取不到。所以认真的分析了 maven 获取 jar 包时候的优先级。
Maven 仓库的分类
仓库分类:本地仓库和远程仓库。Maven根据坐标寻找构件的时候,它先会查看本地仓库,如果本地仓库存在构件,则直接使用;如果没有,则从远程仓库查找,找到后,下载到本地。
1)本地仓库
默认情况下,每个用户在自己的用户目录下都有一个路径名为.m2/repository/的仓库目录。我们也可以在 settings.xml 文件配置本地仓库的地址
2)远程仓库
本地仓库好比书房,而远程仓库就像是书店。对于Maven来说,每个用户只有一个本地仓库,但是可以配置多个远程仓库。
下·
我们可以在 pom 文件配置多个 repository,但是随着项目越来也多我们每次都要在 pom 文件配置比较麻烦,所以我们可以在
settings 文件配置 profile (私服)。这样我们每次创建新项目的时候就可以不用配置 repository。
3)中央仓库
Maven必须要知道至少一个可用的远程仓库,中央仓库就是这样一个默认的远程仓库,Maven 默认有一个 super pom 文件。
maven super pom 文件位置
D:\apache-maven-3.0.4\lib 下的 maven-model-builder-3.0.4.jar 中的 org/apache/maven/model/pom-4.0.0.xml
|
|
这个时候我们就明白了,我们在 settings 文件配置一个 mirror 的 mirrorOf 为 central 的镜像就会替代 ‘中央仓库’ 的原因了。
Maven 镜像
镜像(Mirroring)是冗余的一种类型,一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像。
为什么配置镜像?
1.一句话,你有的我也有,你没有的我也有。(拥有远程仓库的所有 jar,包括远程仓库没有的 jar)
2.还是一句话,我跑的比你快。(有时候远程仓库获取 jar 的速度可能比镜像慢,这也是为什么我们一般要配置中央仓库的原因,外国的 maven 仓库一般获取速度比较慢)
如果你配置 maven 镜像不是为了以上两点,那基本就不用配置镜像了。
注意:当远程仓库被镜像匹配到的,则在获取 jar 包将从镜像仓库获取,而不是我们配置的 repository 仓库, repository 将失去作用
mirrorOf 标签
mirrorOf 标签里面放置的是 repository 配置的 id,为了满足一些复杂的需求,Maven还支持更高级的镜像配置:
external:* = 不在本地仓库的文件才从该镜像获取
repo,repo1 = 远程仓库 repo 和 repo1 从该镜像获取
*,!repo1 = 所有远程仓库都从该镜像获取,除 repo1 远程仓库以外
* = 所用远程仓库都从该镜像获取
私服
私服是一种特殊的远程Maven仓库,它是架设在局域网内的仓库服务,私服一般被配置为互联网远程仓库的镜像,供局域网内的Maven用户使用。
当Maven需要下载构件的时候,先向私服请求,如果私服上不存在该构件,则从外部的远程仓库下载,同时缓存在私服之上,然后为Maven下载请求提供下载服务,另外,对于自定义或第三方的jar可以从本地上传到私服,供局域网内其他maven用户使用。
优点主要有:
1. 节省外网宽带
2. 加速Maven构建
3. 部署第三方构件:可以将公司项目的 jar 发布到私服上,方便项目与项目之间的调用
4. 提高稳定性、增强控制:原因是外网不稳定
5. 降低中央仓库的负荷:原因是中央仓库访问量太大
上面大概介绍了 Maven 仓库概念,接下来我们进入正题
Maven 仓库优先级
为了方便测试,我准备了以下几个仓库
- 172.16.xxx.xxx 远程仓库 (私服)
- dev.xxx.wiki 远程仓库 (远程)
- localhost 仓库 是我自己在本机搭建的一个仓库 (镜像)
- maven.aliyun.com 中央仓库(中央)
本地仓库优先级
Maven 本地仓库拥有该包,而远程、镜像、中央、私服都不包含该包。我们来看下 Maven 是怎么获取的
|
|
从上面可以看出 Maven 一开始就使用本地仓库,并将本地仓库的优先级定制为 10 , 最后 jar 包也在本地仓库找到,Maven 成功打包。
远程仓库优先级
前面我们知道了,本地仓库的优先级是最高的,现在我们继续研究远程仓库的优先级(以下的所有例子,都默认本地仓库不拥有我们需要的包)
这一次我们默认配置 profile(私服)为 172.16.xxx.xxx 远程仓库, repository 为 dev.xxx.wiki 远程仓库,mirror 为本地 localhost 仓库,还配置了一个 mirrorOf 为 central 远程仓库为 maven.aliyun.com 的中央仓库,
以下是配置信息
settings.xml 文件
|
|
pom.xml 文件
|
|
以下是 Maven 拉取包的日志
|
|
好了,看了这么多的配置文件信息和日志信息,我们也总结一下 Maven 远程仓库优先级了。
主要有以下几点:
1.从日志信息我们得出这几种maven仓库的优先级别为
本地仓库 > 私服 (profile)> 远程仓库(repository)和 镜像 (mirror) > 中央仓库 (central)
2.镜像是一个特殊的配置,其实镜像等同与远程仓库,没有匹配远程仓库的镜像就毫无作用(如 foo2)。
3.总结上面所说的,Maven 仓库的优先级就是 私服和远程仓库 的对比,没有其它的仓库类型。为什么这么说是因为,镜像等同远程,而中央其实也是 maven super xml 配置的一个repository 的一个而且。所以 maven 仓库真正的优先级为
本地仓库 > 私服(profile)> 远程仓库(repository)
maven-metadata.xml 文件
Maven Repository Metadata 可用于表示:
1. 一个没有版本的工件:它提供有关该工件的可用版本的信息
2. 快照伪像:它提供有关快照的精确信息
3. 包含Maven插件工件的组:它提供了有关此组中可用插件的信息。
元数据文件名是:
远程存储库中的 maven-metadata.xml,
maven-metadata- <repo-id>.xml在本地存储库中,用于具有repo-id标识符的存储库中的元标记。
以上是 Maven 官网对该文件的解释。
作用
问题:有时候我们更新最新包的时候,会发现最新的包被拉取下来的,但是项目使用的包还是旧的包。所以我们要分析下是什么原因导致的。
首先我们先大概的了解下 maven-metadata.xml 文件。
|
|
其中 lastUpdated 是最中要的一个属性,Maven 更新工程的 jar包时,会比较 lastUpdated 时间戳值,哪个值更大,就以哪个文件为准。
接下来我们看下 Maven 为我们生成了那些文件
我们可以看到 maven-metadata.xml 一共有三个
1. maven-metadata-local.xml 本地的元数据, Maven install 的时候就会生成。
2. maven-metadata-snapshots.xml Maven deploy 时会生成
3. maven-metadata-localhost.xml 远程仓库获取的时候生成 (repository 的 id = localhost)
以上的文件其实都是 Maven 的过渡文件而已
- 例如 maven-metadata-snapshots 就是 Maven deploy 先从远程仓库对应包的 maven-metadata.xml 下载下来,然后修改快照信息后在上传到远程仓库上。
- 例如 maven-metadata-localhost 的作用是在 Maven 在拉取包的时候,会先跟本地 maven-metadata-local 比较下 lastUpdated 时间戳值,值大用哪个。如果是 Mavne 强制更新 的时候(没有强制更新是不会) 会下载远程的 maven-metadata.xml 比较远程,本地,和之前远程保存下来的 maven-metadata 文件。
所以有时候 maven 库上的 jar 包已经更新,而我们总是拉取不到 maven 的包原因就是本地的 maven-metadata-local 的 lastUpdated 比较大。
我们验证下 Maven deploy 例子
|
|
总结
原本以为两天就写好这篇文章,在自己理清思路的时候总是被自己绕晕了。比如在 Nexus 的 Central 配置的中央仓库获取,和 maven-metadata.xml 是如何比较的。
如果以上文章有误,等博客的评论系统搭建起来后欢迎大家指认出来。