2 分钟
Maven Repositories 和 Mirrors
下载流程
Maven 下载依赖的过程中,有两个配置项:Repositories 和 Mirrors。Repositories 是可以在项目粒度的 pom.xml
中配置的,而 Mirrors 只能在 settings.xml
中配置。理解 Maven 下载流程,这两个配置的作用就不言自明了。
- Maven 收集项目 POM 中的 Dependency,发起下载 Dependency 的流程,并递归这个过程直至所有 Dependency 都下载完成
- 下载一个 Dependency 的首先根据配置和项目 POM,准备好两个列表:
- Repositories 列表(最后总会添加默认的 id 为 central 的仓库
https://repo.maven.apache.org/maven2
) - Mirrors 列表
- Repositories 列表(最后总会添加默认的 id 为 central 的仓库
- 遍历 Repositories 列表中的
- 针对每一项 Repository
- 遍历 Mirrors 中的每一项,并匹配 MirrorOf 属性(Repository ID 匹配 MirrorOf),返回第一个匹配的 Mirror
- 如果存在匹配的 Mirror,则向 Mirror 配置的 URL 发起请求
- 如果不存在匹配的 Mirror,则向 Repository 配置的 URL 发起请求
- 如果 URL 下载成功,则完成 Dependency 的下载
- 否则,继续遍历下一个 Repository
- 针对每一项 Repository
- 如果遍历所有的 Repositories 列表都没有下载成功,则直接失败
代码解析参见: https://www.cnblogs.com/ctxsdhy/p/8482725.html
http block 问题
自 Maven 3.8.1 起,maven 禁止了对 Repository URL 为 http 协议的 Repository 进行下载。
禁止的原理就是利用 Mirror 特性实现的,Maven 3.8.1 起,其默认配置文件($MAVEN_HOME/conf/settings.xml
)添加如下配置:
<mirrors>
<mirror>
<id>maven-default-http-blocker</id>
<mirrorOf>external:http:*</mirrorOf>
<name>Pseudo repository to mirror external repositories initially using HTTP.</name>
<url>http://0.0.0.0/</url>
<blocked>true</blocked>
</mirror>
</mirrors>
根据上文提到的下载流程,可以看出,所有 http Repository 都会匹配到该 mirror,然而当前 mirror 又配置了 blocked 为 true,则直接下载失败。
解决的办法为:
- 不使用 http,全部切换为 https
每添加一个 http 的 Repository,都需要在用户配置(
~/.m2/settings.xml
该文件优先级高于默认配置文件) 中添加配置:<mirrors> <mirror> <id>xxx-mirror</id> <mirrorOf>xxx-repo</mirrorOf> <!-- mirrorOf 需要匹配 --> <url>http://maven.aliyun.com/repository/public</url> <!-- <url>https://repo.maven.apache.org/maven2</url> --> </mirror> </mirrors>
关于 mirrorOf
结合上文下载流程。常见的配置为:
*
永远匹配,不建议使用central
maven 中心仓库https://repo.maven.apache.org/maven2
(不包含各种安卓相关的依赖)
最佳配置
不建议使用 mirror
,mirror
很容易出问题。
场景 1:仅包含开源依赖
<settings>
<profiles>
<profile>
<id>personal-repos</id>
<repositories>
<repository>
<id>aliyun-public</id>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<!-- 插件拉取地址 -->
<pluginRepositories>
<pluginRepository>
<id>aliyun-plugin</id>
<url>https://maven.aliyun.com/repository/public</url>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>personal-repos</activeProfile>
</activeProfiles>
</settings>
场景 2:内网私有仓库
假设某公司:
- 部署了一个有私有的 Maven 仓库,该私有仓库只包含公司内部的依赖,不包含公网开源的依赖。
主要研发人员位于国内
<settings> <profiles> <profile> <id>xxx-repos</id> <repositories> <repository> <id>xxx-public</id> <url>https://xxx/repository/public</url> <!-- 如果是 http,则需要在配置 mirror --> <!-- <url>http://xxx/repository/public</url> --> </repository> <repository> <id>aliyun-public</id> <url>https://maven.aliyun.com/repository/public</url> </repository> </repositories> <!-- 插件拉取地址 --> <pluginRepositories> <pluginRepository> <id>xxx-plugin</id> <url>https://xxx/repository/public</url> </pluginRepository> <pluginRepository> <id>aliyun-plugin</id> <url>https://maven.aliyun.com/repository/public</url> </pluginRepository> </pluginRepositories> </profile> </profiles> <activeProfiles> <activeProfile>xxx-repos</activeProfile> </activeProfiles> <mirrors> <!-- 如果内网的 URL 只有 http 协议的话,需要添加这个配置 --> <!-- 其中 mirrorOf 为对应的 Repository 的 ID --> <!-- <mirror> <id>xxx-mirror</id> <mirrorOf>xxx-public</mirrorOf> <url>http://xxx/repository/public</url> </mirror> --> </mirrors> </settings>