前阵子有同事发来消息,说他们那边一个维护了三年的老工程突然构建失败,报错信息跟私服仓库有关。我第一反应不是帮他看代码,而是问了一句:你本地 Maven 版本是不是被升级过了?他沉默了一会儿,回了一句“上周刚装了新版”。这种场景在圈子里太常见了。项目没人动、代码没改、依赖坐标也没变,结果只因为 Maven 本体从 3.6.3 换到了 3.9.x,整个构建环境的行为就变了。
问题暴露之后,他需要的东西其实很朴素——把 Maven 换回原来的历史版本。可等他真去下载才发现,Maven 官网首页只放最新版,想找指定历史版本还得绕几个弯。正好借这件事,把“下载 Maven 指定历史版本”这件事从头到尾捋一遍,包括官方归档目录怎么找、镜像源怎么用、下载完怎么校验、以及怎么避免“下对了版本却因为 JDK 不匹配继续翻车”这一类后续问题。
1. 先别急着下载:你想找的到底是安装包还是依赖坐标
动手之前,我建议你先花一分钟想清楚自己要下载的“Maven 历史版本”到底是哪一类。因为我在各种技术群里见过太多人花半小时找错了地方,最后发现需求根本不是同一个。
1.1 两种主流需求,搜索路径完全不同
第一种需求最常见:我要 Maven 这个工具本身的历史版本。也就是那个解压完带 bin/mvn 命令的二进制分发包,比如 apache-maven-3.6.3-bin.tar.gz。这种需求一般出现在几个典型场景里:老项目的 CI 脚本锁定了某个 Maven 版本;公司私服或者某个插件对 Maven 版本有硬性要求;本地 Maven 被升级后项目构建行为变化,需要回退。这类文件存放在 Apache 官方归档服务器上,跟 Maven 中央仓库是两套体系。
第二种需求则完全不同:我要的是 Maven 中央仓库里某个“依赖”或“插件”的历史版本。比如项目要用 maven-compiler-plugin 的旧版本 3.1,或者某个 groupId:artifactId 在老版本里才有某个类,这时候你需要去 Central Repository 搜索并拿到对应的坐标。
这两类“历史版本”的下载套路截然不同。前者要会看 Apache 的目录结构,后者要会用仓库搜索工具和 dependency:get 命令。如果混为一谈,你会发现用搜索 Maven 安装包的方式去搜依赖,越搜越乱。
1.2 一个快速自测方法
你可以这样自测:如果你要找的东西,下载下来之后需要配置 PATH 环境变量才能用,那它就是 Maven 工具本体,请看第 2 节和第 3 节;如果你要找的东西,是需要写进 pom.xml 的 <version> 标签里、或者通过 mvn dependency:get 拉取的构件,那它是中央仓库里的依赖,直接跳到第 6 节。
另外还要提醒一句:MAVEN_HOME 和本地仓库目录是两码事。下载新 Maven 工具不会覆盖你 ~/.m2/repository 里已经缓存的依赖,所以换版本时不用太担心“本地仓库被清空”,真正需要注意的其实是 settings.xml 的兼容性和 JDK 版本匹配。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Apache Archive 目录怎么一层层找到指定历史版本
Maven 官网首页的下载入口永远指向当前推荐版本,因为它面向的是新用户。想要历史版本,官方给出的正统路径是 Apache 的归档服务器。
2.1 官方入口和目录规律
归档服务器的根地址是 archive.apache.org/dist/maven/。打开之后你会看到按大版本区分的目录,比如 maven-1、maven-2、maven-3。现在绝大多数项目都在用 Maven 3,所以一般直接进 maven-3。
maven-3 目录下是一长串版本号文件夹,从 3.0 到 3.9.x 都有。需要注意一个细节:不同版本的目录层级不一定完全一致,这算是我踩过的一个小坑。早期版本,比如 3.5.x、3.6.x,进入版本号目录后通常还有一个 binaries/ 子目录,真正的安装包在 binaries/ 里面;而部分 3.8.x 和更新的版本,文件名可能直接平铺在版本号目录下。
举个例子,我要找 maven-3.6.3,真实的下载路径是:
text复制https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
如果你在某个版本号目录下没看到熟悉的文件,别急着怀疑眼睛,先看看列表里有没有 binaries 子目录再点进去。我甚至遇到过目录内同时存在压缩包和解压目录的情况,这种一般是发布流程或镜像同步留下的,点文件下载就行。
2.2 安装包文件名拆解
文件名是理解整个下载过程的关键。拿 apache-maven-3.6.3-bin.tar.gz 来说,可以拆成四段:
apache-maven:软件名称,Apache 官方发布的 Maven。3.6.3:版本号。bin:表示这是编译好的二进制发行版,直接可用。tar.gz:打包压缩格式。
对于同一个版本,官方一般会同时提供四种文件:
| 文件名 | 用途 |
|---|---|
apache-maven-3.6.3-bin.tar.gz |
Linux/macOS 使用的二进制包 |
apache-maven-3.6.3-bin.zip |
Windows 使用的二进制包 |
apache-maven-3.6.3-src.tar.gz |
源码包,给想构建 Maven 自己的人用 |
apache-maven-3.6.3-src.zip |
源码包的 Windows 压缩格式 |
绝大多数普通用户只需要 bin 版本,不需要下载 src。如果你是想学习 Maven 源码,那就选 src。Windows 用户优先下 .zip,Linux/macOS 用户下 .tar.gz 更顺手,因为 tar 是系统自带工具。
2.3 下载时的常见“目录空白”状态怎么处理
有几次我给别人指路,对方反馈说“目录打不开”或者“列表是空的”。这时候一般有三种原因:浏览器直接访问某些国外服务器时 HTTPS 握手失败或超时;目录路径拼错;当前网络环境下 archive 域名解析不稳定。
如果是路径拼错,解决办法很简单——从根目录开始逐级点,不要凭记忆拼 URL。如果是网络访问慢,那就用下一节要讲的镜像源方案,不要在官方归档站上死磕。
3. 官方站下载不稳时,我依赖的镜像源与校验方法
Apache 官方归档服务器的下载速度在国内并不稳定。它本身是长期保存历史版本的可靠地方,但如果你只想快速拿一个安装包,镜像站是更现实的选择。
3.1 镜像源 URL 规律与优先级
国内常用的镜像站有很多,比如清华 TUNA、阿里云、华为云,它们会把 Apache 旗下的常用项目同步一份。以清华镜像为例,Maven 历史版本的目录结构和官方归档站几乎一致:
text复制https://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
阿里云镜像也有类似的 /apache/maven/ 目录结构,域名换成 mirrors.aliyun.com 即可。用镜像站有几个好处:下载速度快、断点续传更稳定、不用跟海外服务器抢带宽。
不过镜像站有个天然限制——它只同步 Apache 项目里的常用版本,冷门老版本可能没有被同步。如果你要找的版本在镜像站里确实不存在,那就只能回官方归档站下载。这时候建议直接用下载工具或者浏览器自带的断点下载,尽量不要用不稳定的临时连接去拉大文件。
3.2 SHA-512 校验怎么做
下载完成不是结束,校验文件完整性才是收尾动作。Maven 官方在归档目录中会同时提供对应的校验文件,常见的是 .sha512 或 .sha1 后缀。这个文件的内容是安装包内容的哈希值,用来判断你下载的文件是否完整、是否在传输过程中被破坏。
Windows PowerShell 下可以这样验证:
powershell复制Get-FileHash .\apache-maven-3.6.3-bin.tar.gz -Algorithm SHA512
macOS 或 Linux 下用 shasum:
bash复制shasum -a 512 apache-maven-3.6.3-bin.tar.gz
把命令输出的哈希值和下载目录里那个 .sha512 文件的内容比对,一致说明文件完好。很多老手图省事跳过这步,但如果下载过程断断续续,解压时发现文件损坏,反而要浪费更多时间,这个步骤不值得省。
3.3 下载过程中容易被忽略的三件事
第一,下载工具如果开了多线程加速,最终文件大小跟源站不一致的概率会变高,下载完一定要看一眼文件大小跟页面标注是否一致。第二,浏览器直接下载时如果走了缓存代理,有可能拿到一个过期的错误响应页而不是真正的压缩包,判断方式很简单——文件扩展名和大小对不对。第三,不要同时从官方站和镜像站各下一半文件然后拼接,不同源的包虽然理论上内容一致,但多线程分段下载产生的临时文件格式完全不同,拼出来大概率是坏的。
4. 版本选择表:历史 Maven 不是随手抓的
下载历史版本的最大动力,通常是“新版本不适合当前环境”。那到底哪个历史版本适合你?这不是拍脑袋决定的,至少要同时看 JDK、私服协议和插件生态这三项。
4.1 常见搭配速查表
结合我维护老项目和日常项目积累的经验,这里给出一份“场景优先”的版本选择参考,注意不是官方的绝对兼容矩阵,而是实践中比较稳的组合:
| 场景 | 推荐 Maven 版本 | 理由 |
|---|---|---|
| 维护 JDK 8 时代的老项目 | 3.6.3 | 生态成熟,国内大量教程和 CI 配置都以它为基础 |
| 传统企业项目升级保守 | 3.8.8 | 兼容 JDK 8/11/17,比 3.6.3 新但在 3.8 序列里较稳定 |
| 新项目使用 JDK 17+ | 3.9.x | 对较新 JDK 支持好,插件兼容性也更好 |
| 极其老的 JDK 1.6 项目 | 3.2.x | Maven 3.3 以后对 JDK 1.6 支持明显变差 |
| 需要跟 CI 镜像保持一致 | 以镜像内版本为准 | 避免本地和 CI 行为不一致 |
这张表只是起点,真正拍板前最好还是先看一眼项目里已经跑通的 mvn -v 输出。如果你们项目的 CI 脚本里写死了 maven:3.6.3-jdk-8,那你本地最好也装一个 3.6.3,不要自做主张升到 3.9。
4.2 三个真实兼容性坑
第一个坑是 Maven 3.8.1 开始默认阻止 HTTP 私服仓库。以前很多公司内部私服走的是 http:// 地址,升级到 3.8.1 以上之后,构建直接报 Blocked mirror for repositories。这不是项目出了问题,而是新版 Maven 出于安全考虑默认不访问不加密的 HTTP 仓库。很多人遇到这个报错以后的第一反应是“换回 3.6.3”,这确实是省事的办法,但从根上解决应该是在 settings.xml 里显式配置 mirrorOf。
第二个坑是 Maven 3.6.3 跑在 JDK 17 上可能出现反射访问报错。Maven 自身依赖 Guice 等库,在较新 JDK 上需要额外 JVM 参数才能正常运行。如果你项目必须用 JDK 17,Maven 版本还锁在 3.6.3,构建可能直接失败,这时候不是 Maven 版本有问题,而是 Maven 和 JDK 的搭配不对。
第三个坑是老插件和 Maven 3.9.x 的 API 兼容。Maven 插件的 API 在 3.9 里有一些内部变化,少数停止维护多年的老插件在高版本 Maven 下会报 NoSuchMethodError。这种问题往往比依赖冲突更隐蔽,因为它发生在插件调用 Maven 内部接口的时候。
4.3 用排除法锁版本
我的习惯是这么选版本:
- 先确认项目所在 JDK 主版本。
- 再确认私服地址是
http://还是https://,如果是http://且不打算改私服配置,就避开 3.8.1 以上的版本。 - 查看项目里用到的所有插件,如果存在多年不更新的老插件,避免用最新的 Maven 3.9.x。
- 最后打开官方或镜像站的版本目录,找到一个满足以上条件、且社区口碑相对稳定的版本。
很多人的问题不是找不到历史版本,而是选了“新的历史版本”,结果踩到 JDK 或私服的新坑。
5. 下载后的落地:IDEA 切换、命令行多版本与 Wrapper 锁版
下载安装包只是第一步,解压之后怎么接进日常开发才是实际难点。很多人下对了版本,却在配置阶段把环境搞乱了。
5.1 IDEA 里指定 Maven 版本的正确姿势
IDEA 并不强制使用它内置的 Maven,你可以告诉它“用哪个 Maven”。打开设置,在 Build, Execution, Deployment > Build Tools > Maven 下找到 Maven home path,把它指向你下载解压的目录,比如 D:\maven\apache-maven-3.6.3。改完之后点 Apply,再回到 Maven 工具窗口点刷新按钮,让 IDEA 重新导入。
这里有几个容易忽略的点。一是 User settings file 设置项,默认会指向 IDEA 自带模板生成的 settings.xml,如果你之前配置过阿里云镜像或其他私服地址,要确认那块内容没有被切走。二是 Local repository 路径,IDEA 默认跟着 settings.xml 里的配置走,如果配置文件换了,本地仓库位置可能也会变,导致 IDEA 重新下载一大堆依赖。三是 Runner 标签页里的 JRE 选择,它决定 Maven 进程跑在哪个 JDK 上,如果项目要求 JDK 8,而 Runner 里选了 JDK 17,即使你配了 Maven 3.6.3,构建行为也可能不对。
5.2 命令行统一管理多个 Maven
如果你经常需要维护不同年代的项目,最好的做法不是反复修改系统环境变量,而是把不同版本的 Maven 放在同一个父目录下,互不覆盖,然后通过 shell 函数或者简短命令切换。
例如我本机目录长这样:
text复制/opt/maven/apache-maven-3.6.3
/opt/maven/apache-maven-3.8.8
/opt/maven/apache-maven-3.9.9
切换版本时在 ~/.bashrc 或 ~/.zshrc 里加这样的函数:
bash复制use_maven() {
export MAVEN_HOME=/opt/maven/apache-maven-$1
export PATH=$MAVEN_HOME/bin:$PATH
mvn -v
}
然后执行:
bash复制use_maven 3.6.3
切换完 mvn -v 输出的第一行会明确显示 Apache Maven 3.6.3,确认无误再继续构建。Windows 用户可以写一个简单的 bat 脚本,把要用的 Maven 目录的 bin 提前插到 PATH 最前面。
5.3 项目级锁版:Maven Wrapper 自动下载对应发行版
个人手动切换版本只解决自己机器的问题,团队协作时真正好用的是 Maven Wrapper。它跟 Gradle Wrapper 思路一样,在项目仓库里放一个 mvnw 脚本和 .mvn/wrapper/maven-wrapper.properties 配置文件,里面记录这个项目需要哪个 Maven 版本。
生成 Wrapper 的命令是:
bash复制mvn wrapper:wrapper -Dmaven=3.6.3
执行完以后,项目根目录会多出 mvnw 和 mvnw.cmd。团队成员拿到代码后直接运行:
bash复制./mvnw clean install
它会自动读取配置里的 distributionUrl,把对应版本的 Maven 下载到本地 ~/.m2/wrapper/dists 目录并运行。这样整个团队无论本机装了多新的 Maven,项目构建始终固定在一个版本,从根上杜绝“本地能编、同事编不了”的魔幻场景。
6. 顺带说清:从中央仓库拉指定历史版本依赖/插件的方法
最后再说一种容易被标题误导的场景。很多人在搜索引擎里搜“Maven 历史版本下载”,实际打开一看,发现目标是某个依赖或插件的指定历史版本,不是 Maven 本体。
6.1 用 search.maven.org 找坐标
Maven 中央仓库的所有历史 release 版本都会长期保留,不会因为出了新版本就删除旧版。这是它跟二进制安装包最大的不同。查找方式很简单,打开 search.maven.org,搜索你要的插件或依赖名字,比如 maven-compiler-plugin。
搜索结果页面会列出 groupId、artifactId、Latest 版本,但你想要的是历史版本,所以要点开这个构件详情,在右侧找到 Versions 标签页,里面会按时间倒序列出所有历史版本号。点选 3.1 这类旧版本,页面会给出对应的依赖坐标:
xml复制<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
</plugin>
把这个坐标写进 pom.xml,Maven 会自动从中央仓库下载对应版本。
6.2 dependency:get 直接落地到本地仓库
有些场景你并不想把构件写进项目,只是想把某个指定版本下载到本地仓库备用。这时候可以用 Maven 自带的 dependency:get 插件协议来拉取,命令写法是:
bash复制mvn dependency:get -Dartifact=org.apache.maven.plugins:maven-compiler-plugin:3.1
这里的格式是 groupId:artifactId:version。执行成功后,这个版本会被下载到本地仓库,之后就算项目切换成离线模式,只要能找到这个构件就可以正常引用。
如果你要下载的是带 classifier 的包,比如 sources 包,可以追加:
bash复制mvn dependency:get -Dartifact=groupId:artifactId:version:jar:sources
dependency:get 的好处是它遵循 settings.xml 里的镜像配置。假如你配置了阿里云公共仓库镜像,它也会优先从镜像拉取,速度通常比直接访问中央仓库快。
6.3 老版本在第三方仓库时的补充方案
中央仓库里能搜到的是 Apache 发布到 Central 的构件。但有些框架或工具的老版本只发布在第三方仓库,比如某些商业中间件、某些 Linux 发行版维护的专用构件。这种情况下 search.maven.org 搜不到是正常的。
处理思路有两个。一个是直接打开第三方仓库的 maven-metadata.xml 看历史版本列表,确认你想找的版本确实存在;另一个是在 pom.xml 或 settings.xml 里临时加一个仓库地址,让 Maven 知道去那里找。加仓库时尤其要注意 3.8.1 以上版本对 HTTP 地址的拦截限制,如果第三方仓库只提供 http:// 地址,你得先想清楚是要换 Maven 版本,还是在配置里显式处理。
我在实际工作中最常碰到的,反而是私服管理员误删了某个老版本,导致团队需要从一个第三方仓库临时拉回同一个坐标。这种时候,dependency:get 配合 remoteRepositories 参数能帮你绕过本地仓库的元数据缓存,把指定版本直接抓回来。不过这类操作尽量只在应急时用,长期方案还是得让私服管理员把版本补齐,否则下一次新同事拉代码还是会踩坑。
说到底,“下载 Maven 指定历史版本”这个事,本身不复杂,复杂的是下载之前你要清楚自己找的是安装包还是依赖,下载之后还要处理版本与 JDK、私服、插件的匹配。我自己的习惯是:本机永远留两个常用 Maven 版本,一个偏老一个偏新,老项目用老版本,新项目用新版本;如果团队协作,就在项目里启用 Maven Wrapper,让版本随代码走。这样即使哪天某台机器上的 Maven 被升级了,也不会影响整个项目的构建稳定性。
