Maven 仓库和镜像该怎么配置才不会拉错依赖?
Maven 仓库看似只是下载依赖的地方,实际会影响构建速度、依赖安全和产物可追溯性。一个项目通常会同时接触本地仓库、中央仓库、公司私服和镜像;配置不当时,最常见的问题不是“下载不到”,而是下载到了不该用的版本。理解仓库配置时要分清三个概念:repository 是依赖来源,mirror 是替代某个来源的镜像,server 是认证信息。三者 id 对不上,Maven 不会好心提醒你设计错了,只会在构建时用各种 401、404 或 checksum 错误折磨你。
Maven 会按什么顺序找依赖?
Maven 先查本地仓库,默认在 ~/.m2/repository。本地没有时,再根据有效 POM 和 settings 中的远程仓库配置去下载;中央仓库是默认存在的远程仓库。公司项目一般会让所有请求先走 Nexus 或 Artifactory,由私服代理中央仓库并托管内部包,这样既能加速,也能保留依赖审计记录。
xml<settings> <localRepository>/data/maven-repository</localRepository> </settings>
自定义本地仓库适合 CI 缓存或磁盘隔离,但不建议团队成员随意改路径。路径太分散会导致“我本地有、你本地没有”的错觉,尤其是内部 SNAPSHOT 包没有正确发布时。
私有仓库应该写在 POM 还是 settings?
项目必须知道的仓库地址可以放 POM,但账号密码应该放 settings.xml。更常见的企业做法是 POM 只声明公司仓库 id,settings 里放认证信息和镜像规则。注意 <server><id> 必须和仓库 id 对应,否则认证不会套上去。
xml<repositories> <repository> <id>company-releases</id> <url>https://repo.example.com/repository/maven-releases/</url> <releases><enabled>true</enabled></releases> <snapshots><enabled>false</enabled></snapshots> </repository> <repository> <id>company-snapshots</id> <url>https://repo.example.com/repository/maven-snapshots/</url> <releases><enabled>false</enabled></releases> <snapshots><enabled>true</enabled></snapshots> </repository> </repositories>
xml<settings> <servers> <server> <id>company-releases</id> <username>${env.MAVEN_REPO_USER}</username> <password>${env.MAVEN_REPO_PASSWORD}</password> </server> <server> <id>company-snapshots</id> <username>${env.MAVEN_REPO_USER}</username> <password>${env.MAVEN_REPO_PASSWORD}</password> </server> </servers> </settings>
mirrorOf 怎么配置才安全?
镜像会替代匹配到的仓库,最容易踩坑的是把 <mirrorOf>*</mirrorOf> 指向一个不完整的公共镜像。这样内部私服、插件仓库甚至快照仓库都可能被错误替代。企业内网可以用 *,前提是私服已经代理了所有需要的远程仓库;个人开发更稳妥的是只镜像 central。
xml<mirrors> <mirror> <id>central-mirror</id> <mirrorOf>central</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> </mirror> </mirrors>
企业私服配置的安全边界
公司内网通常会把中央仓库、第三方仓库和内部发布仓库统一代理到一个私服入口,这样便于缓存、审计和阻断高风险依赖。问题是私服不是万能兜底,如果没有同步插件仓库或禁用了 snapshot,Maven 仍然会失败。更稳的做法是在 settings 中配置统一 mirror,在 POM 中只声明项目确实需要的仓库,并把发布地址放到 distributionManagement。账号密码不要写入 POM,也不要写进团队文档截图里;CI 使用环境变量注入,个人电脑可以用 Maven 的密码加密机制或系统凭据管理。
这样配置之后,依赖从哪里来、谁有权限发布、出了问题该查哪一层,都会清楚很多。
追问
repository 和 mirror 到底有什么区别?
repository 是项目声明“我可以从哪里找依赖”,mirror 是 settings 声明“访问某些仓库时改走这个地址”。mirror 的优先级很高,一旦匹配,原仓库 URL 会被替换。取舍是镜像能统一加速和管控,但配置过宽会导致依赖来源被悄悄改掉。边界是 POM 表达项目需求,settings 表达当前机器或组织的访问策略。
releases 和 snapshots 为什么要分开?
release 应该稳定、不可变,snapshot 天生表示还在变化。两者混在一个仓库里,缓存策略、清理策略和审计都会变得混乱。分开后的代价是配置多一点,但能避免生产构建误拉 SNAPSHOT。踩坑最多的是依赖版本写了 1.0-SNAPSHOT,仓库却禁用了 snapshots。
私服认证明明配了,为什么还是 401?
先检查 <server><id> 是否和 repository 或 distributionManagement 里的 id 完全一致。Maven 不是按 URL 匹配认证,而是按 id 匹配。另一个坑是密码里有特殊字符,手写 XML 时转义不正确,或者 CI 环境变量没有注入。排查时加 -X 可以看到 Maven 选择了哪个仓库,但不要把带密码的日志贴到公共渠道。
为什么本地仓库里删了依赖还是拉不到新版本?
可能远程仓库本身没有新版本,也可能 mirror 把请求转到了另一个代理仓库。SNAPSHOT 还受 updatePolicy 影响,Maven 不一定每次都检查远端。取舍上,频繁检查能拿到最新包,但会拖慢构建并增加私服压力。临时排查可以用 mvn -U clean package,长期还是要规范发布版本。
插件仓库需要单独配置吗?
需要时可以配置 <pluginRepositories>,因为插件解析和普通依赖解析是两条配置。很多公司只代理了依赖仓库,却忘了代理 Maven 插件仓库,结果 maven-compiler-plugin 或第三方插件下载失败。边界是常用官方插件通常中央仓库能解决,内部自研插件或受限网络环境才需要显式配置。配置后同样要注意 mirror 是否把它覆盖掉。