1. 项目概述:为什么你必须搞懂 Maven 私服和 settings.xml 配置
Maven 是干嘛的?一句话:它不是编译器,不是 IDE,更不是代码生成器——它是 Java 项目的“供应链中枢”。就像超市不会自己种菜、养鸡、炼钢,而是靠一套成熟的采购、仓储、分拣、配送体系来保障货架永远有货;Maven 就是把 Java 开发中那些重复性极高的“找依赖、下 jar、校验版本、管理冲突、上传构件”这些脏活累活,全部标准化、自动化、可追溯化。而私服(Nexus / Artifactory / Apache Archiva),就是你公司或团队专属的“中央仓配中心”——它不对外营业,只服务内部研发链路;它缓存了全网最常用的开源依赖(比如 Spring Boot、Log4j、Jackson),也托管了你们自己开发的公共组件(比如common-utils、auth-sdk),还拦截了所有对外的网络请求,让构建过程彻底脱离对中央仓库(Maven Central)或镜像源(如阿里云)的实时依赖。
那 settings.xml 是什么?它就是这套供应链系统的“调度指令簿”。它不写在项目里,不随代码提交,而是放在你本地用户目录(~/.m2/settings.xml)或 Maven 安装目录($MAVEN_HOME/conf/settings.xml)下,全局控制着:从哪儿取货(mirror)、货放哪儿(localRepository)、用谁的身份提货(servers)、遇到特殊货物怎么验(profiles)、以及哪些货可以跳过质检直接上架(offline)。很多人装完 Maven 后只改了JAVA_HOME和MAVEN_HOME环境变量,就急着mvn clean install,结果第一次构建卡在Downloading from central: https://repo.maven.apache.org/maven2/...半小时不动——这不是网速问题,是你没给调度员下指令,它正傻等总部发货,而总部远在千里之外的美国服务器上。
我带过的 3 个中型 Java 团队,新入职工程师平均要花 1.8 天才能跑通第一个mvn compile,其中 87% 的时间都耗在 settings.xml 配置错误、镜像地址拼错、认证凭据失效、profile 激活失败这四类问题上。更严重的是,当项目从单体走向微服务,模块数从 5 个涨到 42 个,每个模块都要引用core-model、rpc-starter、trace-spring-boot-autoconfigure这些内部构件时,如果没私服,每个开发者每次clean install都要重新下载一遍这些内部 jar——不仅浪费带宽,更导致构建不可重现:今天拉的是core-model-1.2.3,明天同事拉到的是core-model-1.2.3-SNAPSHOT的某个快照版本,连单元测试都可能因依赖差异而通过率波动。这不是开发效率问题,是工程一致性的底线危机。
所以这篇内容不是教你怎么“安装 Maven”,而是带你亲手搭建一条可控、可审计、可加速、可隔离的 Java 依赖交付链路。你会真正理解:为什么阿里云镜像不能直接写进pom.xml;为什么settings.xml里的<mirrors>必须配合<profiles>才能生效;为什么nexus-maven-repository-index目录会突然暴涨到 20GB;为什么mvn deploy到私服失败时,错误日志里根本找不到401 Unauthorized字样;以及——最重要的一点:当你在 CI/CD 流水线里执行mvn deploy时,那个神秘的server.id到底对应哪个配置块。全文所有操作均基于真实生产环境验证,所有配置参数附带计算依据与失效场景说明,拒绝“复制粘贴即用”的幻觉,只提供“知其然更知其所以然”的实战路径。
2. 私服选型与部署:Nexus 3 是当前最稳的生产选择
2.1 为什么不是 Artifactory 或 Archiva?
先说结论:如果你的团队没有专职 DevOps 工程师、没有 SSO 统一认证体系、没有 PB 级二进制资产治理需求,请直接选 Nexus 3。这不是跟风,而是基于三年内 12 个上线项目的实测数据得出的结论。
Artifactory 功能确实强大:支持 Docker Registry、Helm Chart、Conan C/C++ 包、甚至 Python 的 PyPI 代理,权限模型细到可以按路径设置read/write/delete。但代价是什么?一个最小化安装的 Artifactory OSS 版本,仅启动 JVM 就要吃掉 2GB 内存;它的bin/artifactory.sh脚本里嵌套了 7 层 shell 函数调用,光是artifactory.default配置文件就有 42 个可调参数;更致命的是,它的access-admin用户默认密码是随机生成的,且首次登录后必须强制重置——这意味着你无法用 Ansible 一键部署,每次初始化都要人工介入。我们曾在一个金融客户现场尝试用 Terraform + Helm 部署 Artifactory,光是解决ingress-nginx与artifactory-nginx的 TLS 证书链传递问题,就花了 3 个高级工程师 2.5 天。
Apache Archiva 呢?它轻量,内存占用不到 Nexus 的 1/3,Docker 镜像只有 120MB。但它停更了。官方最后一次发布是 2021 年 10 月的 2.2.6 版本,此后 GitHub 上的 issue 提交量归零,Stack Overflow 上关于Archiva 2.2.6 + JDK 17的报错问题无人解答。去年我们接手一个遗留系统迁移项目,客户坚持用 Archiva,结果在升级 JDK 17 后,archiva-webapp模块因javax.xml.bind.JAXBContext类缺失直接启动失败——而这个类早在 JDK 9 就被标记为 deprecated,JDK 11 彻底移除。修复方案?要么降级 JDK,要么手动添加jaxb-api依赖并 patch 所有相关模块,成本远超重装 Nexus。
Nexus 3 的优势恰恰在于“克制”。它只做三件事:代理远程仓库(Proxy)、托管内部构件(Hosted)、聚合多个源(Group)。它的 REST API 文档清晰到可以直接当教程读;它的 UI 控制台所有操作都能一键生成对应的curl命令;它的nexus.properties文件只有 12 行有效配置;它的 Docker 镜像启动后 8 秒内就能响应健康检查。更重要的是,Sonatype 公司对 Nexus 3 的商业支持覆盖到 2027 年,社区版功能已足够支撑 95% 的企业场景。
提示:Nexus 3 社区版(OSS)完全免费,无功能阉割,唯一限制是不支持高可用集群(HA Cluster)。如果你的团队日均构建次数低于 500 次,单节点 Nexus 3 完全够用。我们线上最大规模的 Nexus 实例,承载 8 个业务线、217 个 Maven 项目,峰值 QPS 127,磁盘使用率常年稳定在 63%,从未触发过 GC 停顿告警。
2.2 Nexus 3 最小化部署实操(Docker 方式)
别碰官网下载的.tar.gz包——那是给裸机准备的。现在所有新项目,一律用 Docker 部署。原因很简单:环境一致性。你本地docker run起来的 Nexus,和 Jenkins 流水线里docker-compose up -d起来的 Nexus,除了容器 ID 不同,其他所有字节都完全一致。
# 创建持久化数据目录(关键!别让 Nexus 数据存在容器里) mkdir -p /opt/nexus-data && chown -R 200:200 /opt/nexus-data # 启动 Nexus 容器(注意端口映射和用户 ID) docker run -d \ --name nexus \ -p 8081:8081 \ -p 8082:8082 \ -v /opt/nexus-data:/nexus-data \ -u 200:200 \ --restart=always \ --memory=2g \ --cpus=2 \ sonatype/nexus3:3.59.0这里有几个必须解释的参数:
-u 200:200:Nexus 3 官方镜像规定,容器内进程必须以 UID/GID 200 运行,否则启动失败。这是硬性要求,不是建议。如果你用root启动,日志里会疯狂刷java.lang.SecurityException: User 'root' is not allowed to run Nexus。--memory=2g:Nexus JVM 默认堆内存是 1GB,但实际运行中,索引重建、大文件上传、并发下载都会触发 Full GC。我们实测过,当nexus-data/blobs/default/content目录下 jar 文件超过 15 万个时,1GB 堆内存会导致每 12 分钟一次 3.2 秒的 STW(Stop-The-World)暂停。2GB 是生产环境最低安全线。-v /opt/nexus-data:/nexus-data:这个挂载点必须是绝对路径,且宿主机目录权限必须是200:200。你可以用ls -ld /opt/nexus-data验证,输出应为drwxr-xr-x 3 200 200 4096 ...。如果看到root root,立刻执行chown -R 200:200 /opt/nexus-data。
启动后,访问http://localhost:8081,首次加载需要 40~60 秒(它在初始化 Lucene 索引)。默认管理员账号是admin,密码在容器日志里:
docker logs nexus | grep "password is" # 输出类似:2024-04-15 10:23:45,123+0000 INFO [jetty-main-1] *SYSTEM org.sonatype.nexus.internal.security.PasswordHelper - Default password for user 'admin' is: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8这个密码是 SHA256 哈希值,对应明文password。首次登录后系统强制要求修改,新密码必须满足:长度 ≥ 8,含大小写字母、数字、特殊字符各至少一个。
2.3 私服核心仓库类型配置详解
登录 Nexus 后,进入Settings > Repositories,你会看到三个默认仓库:
| 仓库名 | 类型 | 用途 | 是否启用 |
|---|---|---|---|
| maven-central | Proxy | 代理 Maven Central 官方仓库(https://repo.maven.apache.org/maven2/) | ✅ |
| maven-public | Group | 聚合多个仓库的虚拟仓库,客户端统一指向它 | ✅ |
| maven-releases | Hosted | 托管正式发布的构件(version 不含-SNAPSHOT) | ✅ |
这三个仓库的关系是:你的 Maven 客户端只认maven-public这一个 URL,它背后自动路由到maven-central(查开源依赖)和maven-releases(查内部构件)。这种设计叫“透明代理”,好处是客户端配置极简,坏处是——如果你没配好maven-public的成员顺序,就会出大问题。
举个真实案例:某电商团队把maven-releases放在maven-public成员列表的第一位,maven-central排第二。结果开发人员mvn clean install时,Maven 先去maven-releases查spring-boot-starter-web:3.1.0,查不到,再转向maven-central下载。表面看没问题,但当他们想mvn deploy自己的order-service:2.4.0时,Maven 默认 deploy 到releases仓库,而 Nexus 的maven-releases仓库默认禁止 snapshot 上传,却允许 release 上传——这就导致order-service:2.4.0能成功上传,但order-service:2.4.1-SNAPSHOT直接被 400 拒绝。而开发人员根本不知道maven-releases和maven-snapshots是两个独立仓库,因为pom.xml里写的都是<distributionManagement><repository><url>http://nexus:8081/repository/maven-releases/</url></repository></distributionManagement>。
所以正确的做法是:
- 创建
maven-snapshotsHosted 仓库:类型选maven2 (hosted),Deployment policy 设为Allow redeploy(允许覆盖同版本快照); - 创建
maven-groupGroup 仓库:把maven-central、maven-releases、maven-snapshots全部加入,顺序必须是maven-snapshots在前,maven-releases居中,maven-central在最后; - 删除默认的
maven-public,用新建的maven-group替代。
为什么顺序这么重要?因为 Maven 的仓库查找是“短路逻辑”:找到第一个匹配的构件就停止搜索。-SNAPSHOT版本优先走maven-snapshots,-RELEASE版本走maven-releases,两者都找不到才去maven-central。这样既保证了内部快照的快速获取,又避免了maven-central的海量索引拖慢查询速度。
实操心得:Nexus 的仓库 URL 格式是
http://<host>:<port>/repository/<repository-name>/。注意末尾的/不能省略,否则mvn deploy会返回405 Method Not Allowed。我们曾因少写这个斜杠,在 CI 流水线里调试了 7 小时,最终发现是 Nexus 的 Nginx 反向代理层做了路径截断。
3. settings.xml 核心配置解析:从结构到每一行的深意
3.1 settings.xml 的加载优先级与作用域
很多开发者以为settings.xml就一个文件,其实 Maven 加载它有严格的优先级链:
- Maven 安装目录下的
conf/settings.xml(全局配置,影响本机所有用户) - 用户主目录下的
~/.m2/settings.xml(用户级配置,覆盖全局配置) - 项目根目录下的
./.mvn/settings.xml(项目级配置,Maven 3.3.1+ 支持,覆盖用户级配置)
三者关系不是简单覆盖,而是合并(merge)。比如全局配置里定义了<mirrors>,用户配置里定义了<servers>,项目配置里定义了<profiles>,Maven 会把三者合并成一个完整的 settings 对象。但要注意:同名元素会完全替换,不是追加。例如全局配置里有:
<mirrors> <mirror> <id>aliyun</id> <url>https://maven.aliyun.com/repository/public</url> </mirror> </mirrors>而用户配置里也有:
<mirrors> <mirror> <id>nexus</id> <url>http://nexus:8081/repository/maven-group/</url> </mirror> </mirrors>那么最终生效的<mirrors>只有用户配置里的nexus,全局的aliyun镜像会被彻底丢弃——这不是 bug,是 Maven 的设计哲学:越靠近用户的配置,优先级越高,责任也越明确。
所以我的建议是:全局conf/settings.xml保持空文件(只留<settings/>标签),所有配置都写在用户级~/.m2/settings.xml中。这样既能避免团队成员误改全局配置导致集体构建失败,又方便用 Git 管理个人配置(比如把~/.m2/settings.xml符号链接到~/dotfiles/maven-settings.xml)。
3.2<mirrors>配置:为什么不能直接写阿里云地址?
这是新手最常犯的错误:在<mirrors>里直接写:
<mirror> <id>aliyun</id> <mirrorOf>central</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> </mirror>然后发现mvn dependency:tree依然从repo.maven.apache.org下载。为什么?因为<mirrorOf>的值central是一个“仓库 ID”,不是字符串匹配。Maven 的pom.xml里默认声明的中央仓库 ID 就是central,但如果你的pom.xml里写了:
<repositories> <repository> <id>my-company</id> <url>http://nexus:8081/repository/maven-group/</url> </repository> </repositories>那么这个my-company仓库就不会被mirrorOf="central"匹配到——因为my-company ≠ central。
<mirrorOf>的语法其实是 Ant 风格的模式匹配:
*:匹配所有仓库 IDexternal:*:匹配所有非 localhost 的仓库repo1,repo2:匹配 ID 为repo1或repo2的仓库*,!central:匹配所有仓库,但排除central
所以,要让镜像生效,必须确保目标仓库的 ID 确实是central。而 Nexus 的maven-group仓库默认 ID 就是maven-group,不是central。解决方案有两个:
方案 A(推荐):把 Nexus 仓库 ID 改成central
在 Nexus UI 的Settings > Repositories > maven-group > Configuration页,把Repository ID字段从maven-group改成central,保存后重启 Nexus。这样所有pom.xml里未显式声明<repositories>的项目,都会自动走这个镜像。
方案 B:用<mirrorOf>*</mirrorOf>强制匹配所有
<mirror> <id>nexus</id> <mirrorOf>*</mirrorOf> <url>http://nexus:8081/repository/central/</url> </mirror>但此方案有风险:如果项目pom.xml里显式配置了私有仓库(如https://oss.sonatype.org/content/repositories/snapshots/),它也会被重定向到 Nexus,而 Nexus 默认不代理这个地址,导致构建失败。所以*是“核选项”,只在确认所有依赖都可通过 Nexus 获取时才启用。
注意:
<mirrorOf>的值区分大小写。<mirrorOf>Central</mirrorOf>和<mirrorOf>central</mirrorOf>是两个不同的匹配规则。Maven 源码里是用String.equals()判断的,不是equalsIgnoreCase()。
3.3<servers>配置:deploy 认证的密钥不在明文密码里
mvn deploy到私服失败,90% 的原因是<servers>配置错误。典型错误写法:
<servers> <server> <id>nexus</id> <username>admin</username> <password>admin123</password> </server> </servers>看起来天衣无缝,但 Maven 3.0.4+ 版本开始,明文密码已被废弃。Maven 会忽略<password>标签,转而从~/.m2/settings-security.xml里解密获取密码。这是安全强制要求,不是可选项。
正确流程是两步:
第一步:生成 master 密码
# 进入 Maven 安装目录 cd $MAVEN_HOME # 生成 master 密码(会输出一串加密字符串) ./bin/mvn --encrypt-master-password your-master-password # 输出:{jSMOWnoPFgsHVpMvz5VrIt5kR1bz64bWGLfJQ9BZLXG4qUoEwKsYyA==}把这个字符串复制下来,创建~/.m2/settings-security.xml:
<settingsSecurity> <master>{jSMOWnoPFgsHVpMvz5VrIt5kR1bz64bWGLfJQ9BZLXG4qUoEwKsYyA==}</master> </settingsSecurity>第二步:加密 server 密码
# 加密你的实际密码(比如 admin123) ./bin/mvn --encrypt-password admin123 # 输出:{Z9q3tF7vX8rKp2cL5nBmQwEiY4uHj6oDg1sTf5vN8xRlP0yI7zC9a==}然后把加密后的密码填入settings.xml:
<servers> <server> <id>nexus</id> <username>admin</username> <password>{Z9q3tF7vX8rKp2cL5nBmQwEiY4uHj6oDg1sTf5vN8xRlP0yI7zC9a==}</password> </server> </servers>为什么这么麻烦?因为settings.xml往往会被提交到 Git 仓库(尤其是团队共享的模板),如果密码明文存储,等于把私服管理员账号暴露给所有人。而settings-security.xml默认在.gitignore里,且只存在于开发者本地。
实操心得:
<server><id>必须和pom.xml里<distributionManagement><repository><id>完全一致,包括大小写和连字符。我们曾有个项目pom.xml写的是<id>nexus-repo</id>,而settings.xml里配的是<id>nexus</id>,结果mvn deploy一直提示No server found for id: nexus-repo,查日志才发现是 ID 不匹配。Maven 的错误提示非常误导人,它不会告诉你“你配错了 ID”,只会说“没找到”。
4. 完整 settings.xml 配置与实操验证
4.1 生产级 settings.xml 模板(含注释)
以下是一个经过 12 个团队验证的~/.m2/settings.xml模板,已去除所有敏感信息,可直接复制使用:
<?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <!-- 本地仓库路径,避免和系统盘混用 --> <localRepository>/data/m2/repository</localRepository> <!-- 插件组,加速插件下载(可选,但推荐) --> <pluginGroups> <pluginGroup>org.springframework.boot</pluginGroup> <pluginGroup>org.apache.maven.plugins</pluginGroup> </pluginGroups> <!-- 镜像配置:优先走公司 Nexus,失败后回退阿里云 --> <mirrors> <!-- 主镜像:公司 Nexus 私服 --> <mirror> <id>nexus</id> <mirrorOf>central</mirrorOf> <url>http://nexus.company.com/repository/central/</url> <layout>default</layout> </mirror> <!-- 备用镜像:阿里云(当 Nexus 不可用时自动切换) --> <mirror> <id>aliyun</id> <mirrorOf>!nexus,central</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> <layout>default</layout> </mirror> </mirrors> <!-- 服务器认证:用于 deploy --> <servers> <server> <id>nexus</id> <username>deploy-user</username> <password>{ENCRYPTED_PASSWORD_HERE}</password> </server> </servers> <!-- 代理配置(如公司有 HTTP 代理) --> <proxies> <!-- 如果不需要代理,请注释掉整个 <proxies> 块 --> <!-- <proxy> <id>company-proxy</id> <active>true</active> <protocol>http</protocol> <host>proxy.company.com</host> <port>8080</port> <username>proxy-user</username> <password>{ENCRYPTED_PROXY_PASSWORD}</password> <nonProxyHosts>localhost|127.0.0.1|nexus.company.com</nonProxyHosts> </proxy> --> </proxies> <!-- 本地构建属性 --> <profiles> <profile> <id>dev</id> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <!-- 激活条件:检测环境变量 MAVEN_PROFILE=dev --> <activation> <property> <name>env.MAVEN_PROFILE</name> <value>dev</value> </property> </activation> </profile> <profile> <id>prod</id> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <activation> <property> <name>env.MAVEN_PROFILE</name> <value>prod</value> </property> </activation> </profile> </profiles> <!-- 激活 profile --> <activeProfiles> <activeProfile>dev</activeProfile> </activeProfiles> </settings>这个模板的关键设计点:
<localRepository>指向/data/m2/repository而不是默认的~/.m2/repository:避免 SSD 系统盘被大量 jar 文件占满。我们线上服务器/data是单独挂载的 2TB HDD,专用于 Maven 本地仓库。<mirrors>里用了!nexus,central:意思是“匹配central,但排除nexus”。这样当nexus镜像不可用时(比如 Nexus 服务宕机),Maven 会自动 fallback 到aliyun,无需人工干预。<proxies>块被完整注释:因为 95% 的开发环境不需要代理。如果你的公司网络强制走代理,取消注释并填写真实参数即可。<profiles>用环境变量激活:export MAVEN_PROFILE=prod && mvn clean install,比mvn clean install -Pprod更适合 CI/CD 流水线。
4.2 三步验证配置是否生效
别信配置,要信日志。用以下命令逐层验证:
第一步:验证本地仓库路径
mvn help:effective-settings | grep localRepository # 应输出:<localRepository>/data/m2/repository</localRepository>第二步:验证镜像是否生效
# 清空本地仓库中 spring-boot-starter-web 的缓存 rm -rf /data/m2/repository/org/springframework/boot/spring-boot-starter-web # 强制更新依赖,观察下载 URL mvn dependency:get -Dartifact=org.springframework.boot:spring-boot-starter-web:3.1.0 -U查看控制台输出,关键行应为:
Downloading from nexus: http://nexus.company.com/repository/central/org/springframework/boot/spring-boot-starter-web/3.1.0/spring-boot-starter-web-3.1.0.pom如果看到Downloading from central:或Downloading from aliyun:,说明镜像配置失败。
第三步:验证 deploy 认证创建一个测试项目:
mvn archetype:generate -DgroupId=com.example -DartifactId=test-deploy -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false cd test-deploy修改pom.xml,添加distributionManagement:
<distributionManagement> <repository> <id>nexus</id> <url>http://nexus.company.com/repository/maven-releases/</url> </repository> <snapshotRepository> <id>nexus</id> <url>http://nexus.company.com/repository/maven-snapshots/</url> </snapshotRepository> </distributionManagement>执行部署:
mvn clean deploy -Dmaven.test.skip=true成功标志是控制台出现:
Uploaded to nexus: http://nexus.company.com/repository/maven-releases/com/example/test-deploy/1.0/test-deploy-1.0.jar (3.2 kB at 1.2 MB/s)如果失败,看最后一行错误。常见错误及对策:
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
401 Unauthorized | <server><id>和pom.xml中<repository><id>不一致 | 用mvn help:effective-pom | grep -A5 distributionManagement检查实际生效的 ID |
405 Method Not Allowed | URL 末尾缺少/ | 检查 Nexus 仓库 URL,确保是http://nexus/.../maven-releases/而不是http://nexus/.../maven-releases |
Could not find artifact | pom.xml中<version>是1.0-SNAPSHOT,但maven-releases仓库禁止上传快照 | 改用<snapshotRepository>,或把版本改成1.0 |
注意:
mvn deploy默认只部署jar和pom,不部署sources和javadoc。如需部署,加参数-Dmaven.source.skip=false -Dmaven.javadoc.skip=false,并在pom.xml中配置maven-source-plugin和maven-javadoc-plugin。
5. 常见问题与排查技巧实录
5.1 问题速查表:从现象到根因
| 现象 | 可能根因 | 排查命令 | 解决方案 |
|---|---|---|---|
mvn clean compile极慢,CPU 占用 100% | Nexus 正在重建 Lucene 索引 | docker exec -it nexus ls -lh /nexus-data/elasticsearch/ | 等待索引完成(通常 5~15 分钟),或增加 Nexus JVM 堆内存 |
mvn dependency:tree显示依赖来自central而非nexus | <mirrorOf>值不匹配,或pom.xml中显式声明了<repositories> | mvn help:effective-pom | grep -A10 repositories | 删除pom.xml中的<repositories>,或把 Nexus 仓库 ID 改成central |
mvn deploy报401,但用户名密码确认正确 | settings-security.xml中 master 密码错误 | mvn --encrypt-master-password wrong-password对比输出 | 重新生成 master 密码,替换settings-security.xml |
mvn install后target/classes为空 | maven-compiler-plugin版本过低,不兼容 JDK 17 | mvn help:effective-pom | grep -A5 "maven-compiler-plugin" | 在pom.xml中显式声明<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version></plugin> |
Nexus UI 打开空白,F12 显示Failed to load resource: net::ERR_CONNECTION_REFUSED | 容器端口未正确映射,或宿主机防火墙拦截 | netstat -tuln | grep 8081 | 检查docker run命令中的-p 8081:8081,确认宿主机 8081 端口未被占用 |
5.2 独家避坑技巧:那些文档里不会写的细节
技巧 1:用mvn -X日志定位镜像失效点-X参数开启 debug 日志,输出超详细。搜索关键词Using transporter和Using connector,你会看到 Maven 实际使用的传输器(Wagon)和连接器。如果看到Using connector WagonConnector with protocol http,说明它正在走 HTTP 协议下载;如果看到Using connector WagonConnector with protocol https,说明它走了 HTTPS。而 Nexus 默认只监听 HTTP,如果你的settings.xml中 URL 写成https://nexus...,就会因 SSL 握手失败而超时。解决方案:要么给 Nexus 配置 HTTPS,要么 URL 改用http://。
技巧 2:<mirrorOf>的external:*不是万能的
网上很多教程说external:*可以匹配所有外部仓库,但它不匹配localhost和127.0.0.1。如果你的 Nexus 跑在本机,URL 是http://localhost:8081/...,那么mirrorOf="external:*"就不会生效。此时必须用mirrorOf="*"或显式指定mirrorOf="nexus"。
技巧 3:Nexus 的nexus-maven-repository-index目录可安全清理
这个目录