十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Maven本地仓库与阿里云镜像配置:settings.xml与mirrorOf

Maven本地仓库与阿里云镜像配置:settings.xml与mirrorOf 1. 从一个卡在 Downloading 的下午说起几乎每个接手过 Java 项目的人都经历过那种进度条不动的窒息感。终端里刷着Downloading from central: https://repo.maven.apache.org/maven2/...然后停在某个BUILD FAILURE上CtrlC 重来一遍还是同一行。这时候你去翻pom.xml依赖坐标写得清清楚楚版本号也没问题——问题不在代码里在 Maven 的下载链路和它落盘的位置上。Maven这个工具的本质工作只有三件事读pom.xml拿依赖坐标、去仓库里找jar、把找到的东西放进一个本地目录供编译使用。而配置本地仓库和阿里云镜像这个动作恰好卡在第二条和第三条上——去哪找镜像和放哪本地仓库。这两件事单独拿出来看都很简单加起来只有十几行 XML但它们决定了你后续每一次clean install是十秒跑完还是十分钟卡死决定了你的 C 盘什么时候被撑爆也决定了团队里十个人构建出来的是不是同一份结果。这篇内容面向的是这样几类人刚装完 JDK 和 Maven、第一次打开settings.xml一脸茫然的新手本地仓库默认堆在系统盘、清理磁盘时才发现~/.m2已经几十个 G 的开发者以及在 CI 或公司内网里需要同时对接私服和外部镜像、被mirrorOf的各种取值绕晕的中级使用者。我不会只丢一段配置让你复制粘贴——为什么是这一行、改错了会发生什么、怎么验证真的生效了这些才是能让你少加几次班的部分。需要提前说明一点下文所有实操都基于主流稳定版本Maven 3.8.x / 3.9.x不同小版本在个别行为上有差异我会在涉及的地方点明。另外所有路径示例同时给出 Windows 和类 Unix 两种写法两边踩的坑其实不太一样。2. settings.xml 有两个位置改错了等于没改这是新手最容易翻车的第一站。很多人改完配置命令行跑一遍发现还是走中央仓库折腾半天最后发现——改的是另一个settings.xml。2.1 全局配置与用户配置的分工差异Maven 启动时会去找settings.xml它有两个候选位置作用范围不同位置典型路径Windows典型路径macOS/Linux作用范围安装目录级%MAVEN_HOME%\conf\settings.xml$MAVEN_HOME/conf/settings.xml本机所有使用该 Maven 安装的用户用户目录级C:\Users\用户名\.m2\settings.xml~/.m2/settings.xml当前登录用户关键的机制在于两者同时存在时用户级的会与安装级合并用户级优先。但对某些元素来说这个合并不是简单覆盖。比如localRepository只取一个有效值而mirrors和servers这类集合元素实际生效的往往是两者叠加后的结果出现同 id 时行为需要谨慎对待。这也是为什么很多人遇到我明明在用户级配了镜像但同事的安装级配置还在起作用的错觉——其实是你俩改的根本不是同一个文件。我在实践中形成的习惯是安装目录级的conf/settings.xml保持原样不动所有个性化配置一律写到用户级的~/.m2/settings.xml。理由很直白——升级 Maven 版本时覆盖安装通常会把conf/目录一起替换掉你在里面写的镜像地址、本地仓库路径会全部丢失。用户级配置则在版本切换、装第二个 Maven 时依然稳定存在。而且公司里如果用共享的开发机改安装级配置会影响其他账号得不偿失。如果~/.m2/settings.xml不存在不需要去别处找模板再改。直接新建一个把根节点settings写全命名空间那几行照抄安装目录里那份即可。Maven 对缺失的配置项有默认值你不需要把所有元素都写上。2.2 怎么确认当前真正生效的是哪一个别再靠猜。Maven 自带一个诊断命令直接把它解析后的完整配置打印出来mvn help:effective-settings这条命令的输出里localRepository的值就是最终生效的本地仓库路径镜像列表也会完整列出来。如果输出里看不到你配的镜像那说明你改的文件根本没被读取。还有一个更轻量的探测方式直接问 Maven 某个具体配置项的值mvn help:evaluate -Dexpressionsettings.localRepository -q -DforceStdout-q压掉无关日志-DforceStdout让结果直接打到标准输出而不是日志文件非常适合塞进脚本里做环境自检。在 CI 流水线里我会用这条命令做前置检查仓库路径不对就直接中断避免后面拉一堆依赖到错误的位置还浑然不觉。顺带提一个容易混淆的点mvn -X输出的调试日志开头会列出 Maven 读取的配置文件路径形如Reading user settings from ...。当你怀疑到底读了哪个文件时这是最直接的证据比翻文档快得多。2.3 IDEA 这类 IDE 会引入第三个变量IDEA 里有两套 Maven 概念需要分清楚Maven home path用哪个 Maven和User settings file用哪个 settings.xml。IDEA 默认会选择捆绑Bundled的 Maven 3它的 settings 文件路径默认指向你的用户目录看起来没问题但如果你手动改成了本地安装的 Maven 版本settings 路径可能仍指向旧位置甚至勾选了 Override 之后指向一个空文件。这里有个我自己踩过的坑某次在 IDEA 里怎么刷新都不生效最后发现User settings file被 Override 成了一个不存在的路径IDEA 不报错静默忽略于是所有配置全部回退到默认值本地仓库又跑回 C 盘了。检查方式是在Settings → Build, Execution, Deployment → Build Tools → Maven页面确认User settings file后面没有出现红色的 Override 提示路径指向你实际编辑的那个文件。另外IDE 面板里显示的依赖树、Maven工具窗口里的刷新按钮走的都是同一套配置。命令行能跑通、IDE 里报找不到依赖八成就是这一处的路径不一致。3. localRepository 的搬迁与路径写法确定好要改哪个文件之后第一个要动的是localRepository。3.1 路径写法里那些会咬人的细节配置项长这样settings xmlnshttp://maven.apache.org/SETTINGS/1.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd localRepositoryD:/maven-repo/repository/localRepository /settings几个必须注意的点Windows 下统一用正斜杠/。反斜杠在 XML 里虽然多数时候能跑但遇到转义序列比如路径里带\t、\n这样的字母组合会被当成控制字符解析出问题时报错信息极难看懂。用/一劳永逸Maven 内部会自己处理平台差异。路径里不要有中文和空格。不是 Maven 本身不支持而是插件生态里总有几个环节没做好转义编译到某个冷门插件时才炸排查成本极高。目录名用maven-repo、m2repo这类纯英文最稳。不要指向一个已经存在大量无关文件的目录。Maven 会在本地仓库根目录下按 groupId 的层级建目录如果指向D:/根目录它会直接把com/、org/铺在你的盘根上清理起来很痛苦。建议放在速度快、容量大的盘上。本地仓库动辄几个 GSSD 上收益很明显尤其是clean install频繁的项目。3.2 已有的本地仓库怎么搬过去假设你要从默认的~/.m2/repository搬到D:/maven-repo/repository。完整步骤完全关闭所有 Java 进程和 IDE。Maven 在下载和写入时会持有文件句柄Windows 上会直接导致部分文件复制失败而复制失败可能不报错只是静默少了一些 jar。完整复制目录。用系统自带的资源管理器复制就行但复制完要对比一下源目录和目标目录的大小、文件数量差不多再继续。用robocopyWindows或rsync -amacOS/Linux比拖动更可靠它们能保留时间戳出问题也好重试。改settings.xml里的localRepository指向新路径。不要急着删旧目录。先按下面的验证步骤跑通一两个项目确认没报缺依赖再删。旧目录暂时改个名字放在那儿当保险。如果是团队协作或者换电脑直接拷贝现成的仓库目录是个省时间的做法因为热门依赖Spring 全家桶、常见工具库占了大头一次性拷过来能省掉几十分钟的下载。3.3 拷贝过来的仓库为什么会不认这里是真正值钱的坑。Maven 3.x 在本地仓库的每个 artifact 目录里都会放一个_remote.repositories文件记录这个 jar 是从哪个远程仓库 id 下下来的。当你在另一台机器、或者换了镜像 id 之后使用这个仓库Maven 会拿当前配置的仓库 id 去比对对不上就认为本地这份不可信转而重新下载——网络好的时候你只会觉得怎么又在下网络差的时候就是直接构建失败。处理方式有两条路老版本可以加-llrlegacy local repository参数让 Maven 用简单的本地仓库管理器忽略这些元数据。但这个参数在新版本里已经被移除别把它当长期方案。通用做法是批量删掉这些元数据文件。在仓库根目录下执行# macOS / Linux find . -name _remote.repositories -type f -delete # Windows PowerShell Get-ChildItem -Path . -Recurse -Filter _remote.repositories | Remove-Item -Force删掉之后 Maven 会把本地存在的 jar 视为可用不再纠结来源。代价是失去了这份 jar 是不是从预期仓库来的这层校验在内网安全要求高的环境里要评估一下。还有一类文件叫*.lastUpdated是下载失败时留下的占位记录。它的作用是阻止 Maven 在短时间内反复重试同一个失败地址默认策略下可能几小时甚至到第二天才重试。你明明已经修好了镜像配置构建却还是立刻失败就是被它拦住了。清理办法同样是批量删除或者临时用-U参数强制刷新mvn clean install -U-U会强制检查所有快照和失败记录的更新代价是每次构建都多一轮网络请求。日常构建不建议常开改完配置、切完镜像的那一两次用它比较合适。3.4 验证本地仓库真的换了改完之后跑这几条缺一不可mvn help:evaluate -Dexpressionsettings.localRepository -q -DforceStdout输出应该就是你配的路径。然后再随便挑一个项目跑一次构建构建完成后去新仓库目录下看有没有新增的目录结构。如果新目录是空的、旧目录却在长文件说明配置没生效回到第 2 节重新确认文件位置。4. 阿里云镜像配置与 mirrorOf 的取值玄机本地仓库解决放哪镜像解决去哪拿。这是第二部分的核心。4.1 一份可以直接抄的配置在settings.xml的mirrors节点里加上这么一段mirrors mirror idaliyun-public/id nameAliyun Public Repository/name urlhttps://maven.aliyun.com/repository/public/url mirrorOfcentral/mirrorOf /mirror /mirrors注意id不要用central这个保留字也不要和其他仓库 id 撞名否则会出现镜像把镜像自己镜像了的诡异循环。我习惯用aliyun-public这种带来源信息的名字方便以后换源时一眼认出来。maven.aliyun.com/repository/public是聚合仓库代理了中央仓库和一批常用第三方仓库日常开发只配这一个基本够用。它走的是 HTTPS不需要额外加证书配置。4.2 mirrorOf 到底该填什么这是整个配置里最容易配错、后果最隐蔽的一项。它的含义是拦截哪些远程仓库的请求改走我这个镜像取值语义如下取值含义适用场景central只拦截 id 为 central 的仓库只想加速中央仓库还需保留私服和其他源*拦截所有远程仓库请求内网环境、只用阿里云一个源external:*拦截所有非 localhost、非 file:// 的仓库本地有 file 仓库时避免误伤repo1,repo2只拦截列出的这几个 id精确控制*,!my-private拦截全部但排除指定 id多仓库共存时最常用新手最常见的操作是直接写*然后发现公司私服里的内部包全都拉不下来了——因为私服请求也被劫持到了阿里云而阿里云当然没有你们公司的内部构件。这类问题在日志里的表现是Could not find artifact com.yourcompany:xxx看起来像依赖坐标写错了实际上是被镜像劫持。正确做法是*,!your-private-id把私服 id 明确排除掉。反过来如果只写central那么pom.xml或者 profile 里声明的其他仓库比如某些项目自带的 jcenter、Google 仓库依然走原地址速度不会改善。所以选哪个值取决于你的项目里到底声明了哪些仓库。可以在项目根目录跑mvn dependency:resolve -X在输出里搜Using mirror和仓库列表就能看清实际走了哪些源。4.3 Maven 3.8.1 之后默认拦截 http 仓库的连锁反应这个变化值得单独拎出来讲因为它的报错信息非常容易误导人。从 3.8.1 开始Maven 在默认配置里内置了一个 id 为maven-default-http-blocker的镜像mirrorOf是external:http:*作用是把所有走 http 协议的外部仓库请求拦掉直接拒绝访问。目的是推动生态全面转向 HTTPS。于是你会看到这样的报错Could not transfer artifact ... from/to maven-default-http-blocker (http://0.0.0.0/): Blocked mirror for repositories不明就里的人会去搜0.0.0.0 是什么镜像越搜越糊涂。真正的原因是你的pom.xml、父 POM 或 profile 里有某个仓库的 url 还是http://开头被这个内置镜像拦了。处理思路有两种优先考虑把那个仓库地址改成https://。绝大多数老仓库现在都支持 HTTPS改一下就好。实在改不了内网自建仓库只提供 http在settings.xml里显式覆盖掉内置拦截镜像。但要注意如果你自己配的镜像mirrorOf写的是*它会顺带覆盖内置的拦截规则副作用是所有 http 仓库都能访问了——这未必是你想要的。我个人在这件事上的态度是只要报这个错先去改 url 协议别急着配镜像绕过去。绕过去只是把问题往后推等到哪天依赖的安全扫描工具报出明文传输风险还是得回来改。4.4 阿里云各个子仓库分别对应什么只配public能覆盖大部分场景但有些特定依赖确实需要单独指向。常见的几个地址和用途仓库地址后缀代理内容什么时候需要单独配/public中央仓库 常用第三方聚合默认首选一个就够/central仅中央仓库想确保只走官方中央内容时/springSpring 相关构件含里程碑版本用到 Spring 的 milestone / RC 版本/googleAndroid、Guava 等 Google 系构件做 Android 或用到 google 系依赖/gradle-pluginGradle 插件相关Gradle 项目或混合构建/apache-snapshotsApache 项目的快照版本需要跟踪 Apache 项目快照/releases、/snapshots通用发布/快照少见特定项目需要一个实用技巧如果你发现某个依赖在阿里云上找不到但中央仓库确实有很可能是镜像同步有延迟。这时候临时给这个依赖单独指向中央仓库或者换回官方源验证一下比死磕配置高效得多。别把镜像同步延迟当成配置错误来排查。5. 多镜像仓库共存时的优先级与排队规则真实项目里很少只有一个源外部公共依赖走镜像公司内部构件走私服某些项目还要挂第三方仓库。这时候谁先被问、谁被跳过是有明确规则的。5.1 先搞清楚 mirror 和 repository 不是一回事很多人把这两个概念混着用导致排查问题时方向全错repository是我告诉 Maven 去哪些地址找依赖写在pom.xml、profile 或父 POM 里作用于依赖解析。mirror是把对某些 repository 的请求转发到另一个地址写在settings.xml里作用于请求转发。镜像的匹配发生在请求发出之前。Maven 拿到一个 repository 对象先看有没有 mirror 的mirrorOf匹配它匹配上了就把 url 换成镜像的 urlid 也换掉。所以日志里出现的是镜像 id 而不是原仓库 id这也是为什么我明明配了私服日志里却是 aliyun这种困惑会出现。还有一个高频误解有人以为配了镜像就不需要pom.xml里的 repository 了。其实对于中央仓库的内容确实如此central 是 Maven 内置的隐含仓库但私服和第三方仓库必须在pom.xml或 profile 里显式声明否则 Maven 根本不知道它们存在镜像也就无从匹配。5.2 用排除语法给私服让路假设公司私服 id 是company-nexus配置应该长这样mirrors mirror idaliyun-public/id urlhttps://maven.aliyun.com/repository/public/url mirrorOf*,!company-nexus/mirrorOf /mirror /mirrors*,!company-nexus的读法是全部拦截但company-nexus除外。多条排除项用逗号分隔*,!company-nexus,!third-party。顺序上有个容易忽略的点Maven 是按镜像在文件里出现的顺序做匹配的第一个匹配上的就生效。所以如果你写了多条 mirror把最精确、最需要优先的放前面最宽泛的比如*放后面。这一点在排查为什么我的精确规则没生效时至关重要。5.3 用 profile 声明多仓库的正确姿势镜像解决的是加速仓库声明解决的是能拿到。如果项目需要额外的第三方仓库推荐放在settings.xml的 profile 里而不是塞进每个项目的pom.xml——一是避免污染项目文件二是换机器时不用改代码。大致结构profiles profile idextra-repos/id repositories repository idcompany-nexus/id urlhttps://nexus.company.internal/repository/maven-public//url releasesenabledtrue/enabled/releases snapshotsenabledfalse/enabled/snapshots /repository /repositories pluginRepositories pluginRepository idcompany-nexus/id urlhttps://nexus.company.internal/repository/maven-public//url releasesenabledtrue/enabled/releases snapshotsenabledfalse/enabled/snapshots /pluginRepository /pluginRepositories /profile /profiles activeProfiles activeProfileextra-repos/activeProfile /activeProfiles这里必须强调的一点pluginRepositories不能漏。Maven 的插件编译、打包、测试用的那些走的是独立的仓库列表。很多人在repositories里配了私服依赖能拉下来但插件依然去中央仓库找在内网环境直接卡住。这个坑我在两个项目上遇到过症状是依赖解析全部成功、一到maven-compiler-plugin执行就超时。另外snapshots默认是关闭的。如果你的项目依赖内部快照版本必须显式打开否则会一直提示找不到构件。但生产构建里依赖快照是有风险的——同一个版本号的内容随时可能变构建不可复现。我的做法是本地开发打开、CI 上关闭用固定的发布版本号做正式构建。6. 配置生效的验证与故障排查链路配置写完不等于生效下面是我实际排查时按顺序走的一套流程。6.1 三条命令确认配置真正落地# 1. 看最终生效的 settings mvn help:effective-settings # 2. 单独确认本地仓库路径 mvn help:evaluate -Dexpressionsettings.localRepository -q -DforceStdout # 3. 看仓库匹配和镜像转发过程 mvn dependency:resolve -X | grep -i Using mirror第三条命令在 Windows 下把grep换成findstr或者干脆把输出重定向到文件再搜。重点看两件事请求被转发到了哪个 url以及有没有出现意料之外的仓库。6.2 明明配了镜像却还在走中央仓库这是最高频的问题按可能性排序的排查清单现象可能原因确认方式日志显示访问 repo.maven.apache.orgmirrorOf没匹配上 central 的 id检查pom.xml是否重定义了 id 为别的名字的 central 仓库只有部分依赖走镜像mirrorOf是central其他仓库未覆盖改成*或补上对应 id完全没生效改错了 settings.xml 文件用-X看Reading user settings fromIDE 里不生效IDEA 的 settings 路径被 Override检查 Maven 设置页面的路径提示配置生效但下载慢镜像同步延迟或网络抖动换/central单独测试或对比官方源关于第一行特别说明一下有的项目父 POM 里会把中央仓库重定义为自定义 id 的仓库对象这时mirrorOf写central就匹配不上因为它已经不是 id 为central的那个了。这种情况用*或者写上实际的 id 才能覆盖。6.3 校验和失败、证书错误、403 怎么处理这几种报错信息不同处理思路也不同Checksum validation failed下载下来的文件与校验值不符。绝大多数是网络传输中途出错或者镜像同步尚未完成。先本地删除对应目录包括.lastUpdated和.sha1文件然后带-U重试一次。反复出现的话说明该镜像的这个构件有问题临时换源验证。PKIX path building failed/unable to find valid certification path本机信任库不认服务端证书。常见于公司网络做了中间代理。正规做法是把内部 CA 证书导入 JDK 的cacerts而不是关掉校验-Dmaven.wagon.http.ssl.insecuretrue这类参数只能临时用绝不能进团队配置。401 Unauthorized/403 Forbidden访问私服时凭证缺失或错误。这时要在settings.xml的servers里配置 id 与仓库 id 一致的账号密码。注意servers里的 id 必须和 repository 或 mirror 的 id 严格对应对不上就是白配。servers server idcompany-nexus/id usernameyour-account/username passwordyour-password/password /server /servers密码明文写在settings.xml里有泄露风险。更稳妥的做法是使用 Maven 的密码加密功能mvn --encrypt-password或者交给 CI 的密钥管理机制注入。个人开发机上问题不大但配置进版本库就危险了。6.4 完全离线环境下的做法有些机器不允许外网访问但项目又必须能构建。这时候的思路是提前把仓库喂饱在一台能联网的机器上用相同的 Maven 版本和相同的项目跑mvn dependency:go-offline。这个命令会尽可能把项目声明的依赖和插件都下到本地仓库。如果有测试阶段才用到的依赖go-offline不一定全覆盖可以再跑一次完整的mvn clean install -DskipTests把插件也补齐。把整个repository目录打包拷到离线机器的新本地仓库路径下。按 3.3 节清掉_remote.repositories和*.lastUpdated。构建时加-o进入离线模式强制 Maven 只用本地仓库mvn clean install -o离线模式的价值不只是省网络它还能保证构建结果稳定——避免某次构建恰好拉到了一个刚更新的快照版本导致前后两次结果不一致。在需要严格复现的环境里这个特性比省时间重要得多。7. 日常使用中值得固化的几个习惯配置本身是一次性的但围绕它形成的习惯会持续影响效率。7.1 clean install 的时候镜像和本地仓库分别在忙什么理解这个流程能帮你在遇到卡顿时快速判断方向。mvn clean install大致经历清理 target 目录 → 解析pom.xml的依赖树 → 检查每个依赖是否在本地仓库存在且完整 → 缺失的走镜像下载 → 编译 → 测试 → 打包 → 安装到本地仓库。只有在第四步才会真正走网络。如果构建卡在编译或测试阶段改镜像配置一点用都没有反过来如果卡在依赖解析那八成就是镜像、本地仓库或者网络的问题。看日志里有没有Downloading from这一行就能快速分流。本地仓库在最后一步也有角色install会把你自己构建出来的 artifact 放进本地仓库供其他本地项目通过依赖坐标引用。所以多模块项目里本地仓库路径如果配得混乱会出现上个模块刚 install 完下个模块却找不到的情况。7.2 团队统一配置与版本控制团队里每个人自己配一套 settings稍微复杂点就出分歧。我的做法是维护一份共享的settings.xml模板放进内部仓库包含镜像地址、本地仓库建议路径、profile 声明和仓库地址但不包含任何账号密码。新人入职拉下来放到用户目录改几个占位符就能用。模板里我会额外加一段注释块写清楚每一项为什么这么配、什么时候需要改。这东西看着不起眼但能省掉大量为什么我的构建和别人不一样的沟通。同时镜像地址要挑一个相对稳定的别用带临时路径或者会变动的地址——某次镜像地址调整团队里十几个人的配置全要跟着改那种体验不想再来第二次。7.3 版本升级后需要复查的几项Maven 的默认行为在小版本之间会有变化3.8.1 引入 http 拦截就是典型例子。升级后建议复查本地仓库路径有没有被重置回默认位置安装级配置被覆盖时会发生。镜像是否还在生效特别是依赖 http 的内网仓库是否突然报 blocked。新版是否移除了你在用的命令行参数。-llr就是已经消失的一个脚本里如果还带着它升级后会直接报参数不认识。JDK 版本兼容性。新版 Maven 对 JDK 的最低要求会提高老项目在旧 JDK 上跑可能直接启动失败。升级前把当前的mvn -version和mvn help:effective-settings输出存一份出问题时可以快速对比出哪一项变了这比凭记忆猜测快得多。7.4 磁盘占用的定期维护本地仓库是会持续膨胀的尤其是长期开发多个项目之后。几个我常用的清理方式找那些明显过时的快照版本。快照是按时间戳存的同一个版本号可能攒了几十个文件夹用mvn dependency:purge-local-repository可以针对当前项目清理并重新解析。定期看看最大的目录在哪。往往是某个大型框架的不同版本各存了一份如果项目已经统一升级旧版本可以删。别删org/apache/maven/plugins下面的东西。这是 Maven 自己的插件依赖删掉之后下次构建还得重新下而且很容易在下到一半的时候断网反而更麻烦。我在实际使用中的体会是——这套配置真正的价值不在于省了多少下载时间而在于它把环境不确定性这件事收窄了。本地仓库定死了构件落在哪里镜像定死了请求发往何处两者合起来你才能对着日志说清楚一次构建到底发生了什么。而只要能做到这一点剩下的问题无非是查表、对照、改一行配置的事。
返回列表