上周新同事入职,领了台新电脑,第一天就卡在装环境上。按网上一堆教程装完JDK,java -version能出结果,可一敲mvn -version就报"不是内部或外部命令"。这种问题我见得太多了,十有八九是环境变量PATH里少配了Maven的bin目录,或者JAVA_HOME指错了位置。Java、Maven安装这事儿说简单是真简单,解压完配个路径就行,但说麻烦也真麻烦——版本怎么选、镜像仓库怎么配、本地仓库放哪、为什么明明本地有包却还是引不进来,这些坑不踩一遍根本记不住。这篇就把我从零到一跑通Java和Maven的完整过程写清楚,适合刚入手Java生态的新人,也适合那些每次换电脑都要重新折腾一遍环境的老手。
1. 装JDK之前,先把版本和发行版选明白
很多人一上来就搜"Java安装",其实Java这十几年的版本策略早就变了。Oracle从Java 8之后改成了半年一个版本,真正适合生产用的只有LTS(长期支持)版本。目前项目里最主流的还是Java 8(对应JDK 1.8),因为大量老项目、老框架都构建在它之上;稍微新一点的公司会直接上Java 17或者Java 21。如果你今天要新装环境,我建议直接选Java 21,原因很简单:Spring Boot 3.x要求的最低版本就是17,而21作为最新LTS,生态兼容性已经足够成熟。
1.1 发行版怎么选:Oracle JDK还是OpenJDK
先把这个争议说透。Oracle JDK从Java 8u211之后,Oracle 11开始就不再免费用于商业用途了,个人开发还好,公司内部用就要留意授权问题。OpenJDK是Oracle JDK的开源底子,功能几乎一致,日常开发完全够用。现在市场上常见的免费发行版有:
- Eclipse Temurin(Adoptium项目出品,社区认可度最高)
- Amazon Corretto(AWS维护,更新很及时)
- 阿里云Dragonwell(对国内网络友好,下载速度快)
- Microsoft OpenJDK(微软出品)
我自己的习惯是:个人学习用Eclipse Temurin,公司项目如果运维指定就用对应版本。国内网络环境下,从Adoptium官网下载可能会慢,可以走国内镜像或者用阿里云Dragonwell的下载页。
1.2 下载完先确认目录结构
JDK安装包有种形式,一种是exe/msi安装向导,一种直接是zip/tar.gz压缩包。我强烈推荐压缩包,因为解压即用,不需要安装程序往注册表里写东西,卸载也干净。解压后你会看到这样的目录:
jdk-21/ ├── bin/ # java、javac、jar等可执行命令都在这 ├── conf/ # 配置文件,比如security目录下的java.security ├── include/ # C/C++头文件,涉及JNI调用时需要 ├── jmods/ # JMOD模块文件,构建jre用的 └── legal/ # 开源协议声明装完之后第一件事不是配环境变量,而是先运行bin下的java -version确认解压出来的JDK能正常执行。这一步能排除"包损坏"和"32位/64位不匹配"的问题。
1.3 平时根本碰不到的坑:JAVA_HOME指向jre还是jdk
旧版JDK在安装目录下面自带一个jre目录,很多人配置JAVA_HOME时手滑指到了jre上。Java 9之后官方不再提供独立的jre目录,所以现在这个问题少了,但我还是见过有人把JAVA_HOME配到类似C:\Program Files\Java\jdk-21\bin的。这个一定要纠正:JAVA_HOME必须指向JDK的根目录,也就是包含bin目录的上一层,不是bin本身,也不是jre。
2. 环境变量配置:JAVA_HOME和PATH的配合逻辑
环境变量配置是整个安装过程中最核心也最容易翻车的一步。很多人直接把JDK的bin目录写进PATH里,用是能用,但下次换个JDK版本就得去改PATH,改错了又得折腾半天。正确做法是先用JAVA_HOME保存JDK根路径,然后在PATH里引用JAVA_HOME,形成"改一个变量就能全局切换版本"的结构。
2.1 为什么必须配置JAVA_HOME
JAVA_HOME本身不是一个Java运行必须的变量,但它是整个Java生态的约定。Tomcat、IDEA、Maven、Gradle这些工具启动时会主动去读JAVA_HOME,找不到就报错。如果你只在PATH里写了java命令,Maven虽然能通过PATH找到java,但很多脚本内部还是习惯查JAVA_HOME,查不到就会出现各种诡异问题。
另外,把JAVA_HOME单独提出来,以后升级版本只需要改JAVA_HOME这一个值,PATH里所有引用它的路径自动跟着变。
2.2 Windows、macOS、Linux三种配置方式
Windows下我推荐用图形界面配,因为不容易出错:
- 右键"此电脑" → 属性 → 高级系统设置 → 环境变量
- 新建系统变量:变量名
JAVA_HOME,变量值填JDK根目录,比如D:\dev\jdk-21 - 找到PATH变量,编辑,新增一行
%JAVA_HOME%\bin - 注意Windows 10以上版本PATH是分行显示的,不要加
;分隔符了,直接在列表里加
macOS和Linux的做法更直白,编辑~/.zshrc(macOS新默认)或~/.bashrc:
export JAVA_HOME=/usr/local/jdk-21 export PATH=$JAVA_HOME/bin:$PATH配置完执行source ~/.zshrc让变量生效。
2.3 验证环境变量配置成功的标志
配完一定不要急着装Maven,先开一个新的终端窗口(这点很重要,旧窗口不会刷新环境变量),依次执行:
java -version看到类似java version "21.0.2" 2024-01-16 LTS的输出就对了。然后执行:
javac -version这个命令会输出Java编译器版本。很多人只测了java不测javac,导致后来Maven编译项目时报javac: not found,白折腾半天。
再顺手验证一下JAVA_HOME本身:
echo %JAVA_HOME% # Windows echo $JAVA_HOME # macOS/Linux输出必须是JDK根目录路径,后面不能有多余的空格和\bin。
3. Maven下载与基础安装:和JDK不同的地方
Maven本质是一个构建工具,它的安装过程和JDK几乎一样——下载压缩包、解压、配环境变量。区别在于Maven本身不运行什么程序,它只是用Java写的一堆脚本,所以它依赖JAVA_HOME,而不是反过来。
3.1 版本选择:认准3.9.x
Maven的版本命名和Java不一样,没有LTS的概念,但社区实际上把3.2.5、3.5.4、3.6.3这些版本当成了"稳定到发指"的版本。目前官方主推的是3.9.x系列,它的父级版本跟3.8.x相差挺大,对Java 8到Java 21的兼容性都做了修复。我在生产项目里用3.9.6和3.9.9都跑过,没出过问题。
网上偶尔能看到"Maven 3.7下载"之类的关键词,实际上Maven官方从来没发布过3.7版本,这多半是把Apache软件基金会其他项目的版本号记混了。选版本的原则很简单:去Apache官方下载页看当前最新release,选3.9.x而不是3.8.x,别用SNAPSHOT版。
3.2 Maven目录结构说明
解压Maven后你会看到一个名为apache-maven-3.9.6的目录(这是官方发布包的标准命名),里面关键的目录是:
apache-maven-3.9.6/ ├── bin/ # mvn、mvn.cmd脚本 ├── boot/ # maven自己加载的类加载器 ├── conf/ # settings.xml全局配置文件 └── lib/ # maven运行时依赖的大量jar包conf/settings.xml是全局配置文件,它控制着本地仓库位置、镜像源、代理、服务器认证等关键行为。这个文件在后面的实战中会反复折腾,所以先记下它的位置。
3.3 Maven的环境变量和验证
JDK的JAVA_HOME配好后,Maven需要的是MAVEN_HOME和PATH,配置原理一模一样:
- Windows新建系统变量
MAVEN_HOME,值为D:\dev\apache-maven-3.9.6 - PATH里新增
%MAVEN_HOME%\bin - macOS/Linux在
.zshrc里加:
export MAVEN_HOME=/usr/local/apache-maven-3.9.6 export PATH=$MAVEN_HOME/bin:$PATH配置完新开窗口执行mvn -v,正常输出里必须有Maven home、Java version、Java home三行信息。如果Maven home和Java version都能显示,但最后一行Java home路径是错的,那说明你JAVA_HOME没配对,Maven虽然勉强能找到java命令,但后续编译时很可能会报class错误。
4. settings.xml实战:本地仓库、镜像源与多仓库优先级
Maven装完,如果你什么都不动,直接执行mvn help:system,它会默认到用户目录/.m2/repository下建仓库,然后去中央仓库下载一堆初始依赖。默认行为有两个问题:一是国内访问Maven中央仓库经常抽风,速度以KB为单位;二是默认本地仓库放在C盘,系统盘空间越来越紧张。这些都要通过改settings.xml来解决。
4.1 第一个要改的:localRepository
<localRepository>标签指定依赖jar包下载后存放的本地目录。我一般放D盘或单独的数据盘,比如:
<localRepository>D:/maven-repo</localRepository>注意两个细节:路径不支持D:\maven-repo这样的反斜杠写法,建议统一用正斜杠或者双反斜杠;这个目录如果不存在,Maven会自动创建,不用预先建。改完本地仓库,以后所有项目的依赖都从这个目录读,磁盘空间不足时也能一眼看出哪块占得多。
4.2 配置阿里云镜像仓库
这是国内用户最需要的一步。Maven中央仓库(repo.maven.apache.org)服务器在海外,下载速度慢是常态。配置镜像源的思路是:让Maven不去中央仓库,而是从阿里云的镜像同步依赖。
在settings.xml的<mirrors>节点下加:
<mirror> <id>aliyunmaven</id> <name>aliyun maven public</name> <url>https://maven.aliyun.com/repository/public</url> <mirrorOf>central</mirrorOf> </mirror>这段配置的作用:把所有中央仓库的请求都转发给阿里云。<mirrorOf>central</mirrorOf>意思是只镜像Maven的central仓库,不会影响后续你追加的第三方仓库。如果你还需要Spring、JBoss等单独的仓库,阿里云有一个聚合地址https://maven.aliyun.com/repository/public,它已经把central和jcenter都聚合进去了,日常开发这一个地址就够用。
4.3 多个镜像仓库的配置规则
公司接入私服后,settings.xml里会有多个mirror。这里有一个最容易踩的坑:Maven对同一个仓库只认第一个匹配到的mirror,后面的不会生效。举例说明:
<mirrors> <mirror> <id>aliyun</id> <url>https://maven.aliyun.com/repository/public</url> <mirrorOf>central</mirrorOf> </mirror> <mirror> <id>company</id> <url>http://repo.company.com/repository/maven-public/</url> <mirrorOf>*</mirrorOf> </mirror> </mirrors>如果company的mirrorOf是*(匹配所有),那阿里云那条配置就形同虚设,因为所有仓库请求都优先命中了company。如果你的私服没有代理外部中央仓库的功能,建议把私服的mirrorOf明确指向*,然后让私服去同步中央仓库;如果私服只放内部依赖,外部依赖还是要走阿里云,那就应该把company的mirrorOf限定为releases, snapshots这种内部仓库id。
4.4 profiles里配置仓库而不是镜像
镜像(mirror)解决的是"请求转发给谁"的问题,仓库(repository)解决的是"从哪些地址拉依赖"的问题。两者很容易混。如果你的私服必须靠内部认证才能访问,那更合理的做法是在<profiles>节点指定repositories:
<profile> <id>company</id> <repositories> <repository> <id>company-repo</id> <url>http://repo.company.com/repository/maven-public/</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>company-plugin-repo</id> <url>http://repo.company.com/repository/maven-public/</url> </pluginRepository> </pluginRepositories> </profile>注意plugin仓库和依赖仓库经常要分开配,因为Maven默认的插件仓库是central,如果你私服没同步插件索引,很多构建插件会拉不到。
5. 高频踩坑:从.m2目录到依赖引用失败的完整排查链路
配置全都弄对了,不代表后面就不会遇到问题。这里把我在实际环境中碰到过的四个高频故障完整写一遍排查思路,每一个都对应了热搜里的高频关键词。
5.1 .m2目录下没有settings.xml怎么办
新装Maven后,用户目录下自动生成~/.m2,但里面只有repository目录,没有settings.xml。很多人误以为配置文件丢了,其实这是正常现象。~/.m2/settings.xml是需要手动从Maven安装目录的conf/settings.xml复制过去的。
复制一份到用户目录的目的是:把"全局配置"变成"用户级配置",避免以后升级Maven时把自定义配置覆盖掉。操作方式:
cp /usr/local/apache-maven-3.9.6/conf/settings.xml ~/.m2/settings.xml复制完再改~/.m2/settings.xml里的localRepository和mirror配置。Maven读取配置的顺序是全局settings.xml先加载,然后加载用户settings.xml,用户配置会覆盖全局配置,所以日常改用户级文件即可。
5.2 本地仓库明明有jar包,却还是报找不到依赖
这是最让人抓狂的问题之一。现象是:~/.m2/repository里能找到org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar,但IDEA里跑项目时依然提示"cannot resolve symbol"或者编译失败。
优先排查这三件事:
坐标是否写错。去本地仓库的目录结构里看路径,路径里的目录层级就是groupId、artifactId的映射。比如
org/apache/commons对应的groupId是org.apache.commons,多一个点少一个点都会导致找不到。是否只下载了.jar没下载对应.pom文件,或者.pom损坏。Maven通过pom文件解析依赖树,缺pom几乎等于依赖不存在。解决方案是把该依赖对应的整个groupId目录从本地仓库删掉,然后强制更新一次:
mvn -U clean install-U参数会强制检查远程仓库的最新版本,把缺失文件重新下载回来。
- IDEA的索引缓存没刷新。IDEA的Maven面板中有个刷新按钮,点一下重新导入,很多时候"引不进来"只是IDE界面上的缓存问题,命令行里
mvn compile反而是通过的。
5.3 编译报错:找不到com.sun.image.codec.jpeg.JPEGCodec
这个错误在Java 8项目里很常见,但放到Java 15以上跑就会崩。根本原因是com.sun.image.codec.jpeg这个包在JDK早期版本里属于内部API,Java 9模块化之后默认不再对外暴露。排查过程是我从一版老代码里真实踩到的:
- 第一步,看到报错先确认JDK版本:
java -version - 第二步,在项目pom.xml里查
maven-compiler-plugin配置的source和target - 第三步,确认代码里是否直接import了
com.sun.image.codec.jpeg
解决方案有两个,最稳妥的是替换成标准API,比如用javax.imageio.ImageIO或者com.github.jai-imageio库。如果只是老代码短期过渡,也可以给编译器加--add-exports java.desktop/com.sun.image.codec.jpeg=ALL-UNNAMED,但这只适合临时环境,不建议带到生产构建配置里。
5.4 Maven下载依赖速度缓慢,甚至卡死
如果你的settings.xml里已经配了阿里云镜像还是慢,那就再查三件事:
- 确认镜像配置真的生效了。可以执行:
mvn dependency:resolve -X开启调试日志后搜索Downloading,看实际下载URL是不是阿里云的地址。如果继续指向repo.maven.apache.org,说明mirror配置没生效,检查mirrorOf匹配规则。
确认本地仓库路径没有权限问题。Windows下如果放在
C:\Program Files目录下,权限不足会导致每次下载都失败或极慢,最好把仓库放到用户目录或数据盘。是不是有私有库在拖后腿。某些依赖直接从私服拉,而私服没有缓存,首次解析会极慢。这种情况要么在私服上做同步缓存,要么在profile里单独配置外部代理地址。
5.5 IDEA里的Maven配置和命令行不一致
很多人遇到这种情况:命令行mvn clean install跑得好好的,IDEA一运行就报错。核心原因通常是IDEA使用的Maven版本和设置跟命令行不一致。
IDEA设置里需要检查三处:
- Maven home path:必须指向你解压的Maven目录,比如
D:\dev\apache-maven-3.9.6,不要用IDEA自带的Bundled Maven - User settings file:指向
~/.m2/settings.xml,不要用默认的全局配置 - Local repository:显示为本地仓库路径,确认它读取到了settings.xml里的配置
如果改完IDEA还是报错,执行一次File -> Invalidate Caches / Restart,把IDE的缓存清掉再重新导入项目。IDEA的Maven索引有时候会非常顽固,不重启不生效。
6. mvn命令实操:从clean install到依赖树排查
Maven配置全部搞定后,项目构建这块必须掌握几个核心命令,它们能解决90%的日常问题。
6.1 最常用的构建组合
mvn clean install这条命令是最标准的全量构建流程:
- clean:清空target目录,删除上一次编译的class文件
- install:将项目打包并安装到本地仓库,供其他模块引用
单模块项目直接用就行。多模块项目里,install命令会按依赖顺序构建所有模块,这也是为什么很多人在根目录执行一条clean install就能全部打好的原因。
6.2 跳过检查的两种方式
构建老项目时经常碰到的报错是checkstyle、spotbugs或者测试用例失败导致构建中断。临时需要跳过的话:
mvn clean install -DskipTests mvn clean install -Dmaven.test.skip=true两者区别在于:-DskipTests是编译测试类但不执行测试用例,-Dmaven.test.skip=true是连测试代码都不编译。另外跳过静态检查通常用-Dcheckstyle.skip=true,要确认项目实际使用的是哪个插件。
6.3 查依赖冲突的利器
依赖冲突是Java项目最隐蔽的问题之一。两个库传递依赖了同一个jar的不同版本,Maven默认采用"最近声明优先",但偶尔会踩到版本不兼容的雷。排查命令:
mvn dependency:tree这条命令会打印出整个依赖树。关键在于看有没有同一个groupId下出现两个不同version。比如:
com.fasterxml.jackson.core:jackson-databind:2.15.2 com.fasterxml.jackson.core:jackson-databind:2.17.1这种结局一般就是引入<dependencyManagement>把版本统一管起来。用mvn dependency:tree -Dverbose还能看到依赖是被哪条链路引进来的,排查的时候多这层信息量就差很多。
6.4 Maven命令行常用参数速查
| 参数 | 作用 | 示例 |
|---|---|---|
-U | 强制更新SNAPSHOT依赖和快照 | mvn compile -U |
-pl | 指定构建模块(多模块项目) | mvn install -pl module-a |
-am | 构建指定模块及其依赖模块 | mvn install -pl module-a -am |
-DskipTests | 跳过测试执行 | mvn package -DskipTests |
-X | 打开调试日志 | mvn install -X |
-o | 离线模式,不访问网络 | mvn compile -o |
离线模式在断网环境下很有用,前提是之前已经完整下载过依赖。如果离线模式下报缺包,那说明本地仓库没有该依赖,切回在线模式跑一次再切离线。
7. 安装完之后的健康检查清单
环境装完,我习惯按下面这套清单做一遍快速体检。这些检查项看着简单,但能拦截掉日后80%的"莫名其妙"问题。
java -version输出正常,确认版本符合预期javac -version输出正常,编译器可用echo $JAVA_HOME或echo %JAVA_HOME%指向JDK根目录mvn -v输出的Java home一行与JAVA_HOME一致mvn help:system能成功执行并下载初始化文件- 打开IDEA的Maven设置面板,三处路径与命令行一致
- 用
mvn dependency:tree构建一个已有项目,验证依赖解析正常
这一步体检完了基本不会再出现"配置半天最后才发现JDK版本不对"的尴尬。
如果一切正常,下一步就进入业务开发了,比如用Maven创建第一个Spring Boot项目。我个人在实际操作中的体会是:Java和Maven安装这件事,第一次花两小时捣鼓,第二次十分钟以内就能搞定。关键在于把每一处配置背后的原因弄明白——为什么配JAVA_HOME、为什么改镜像、为什么本地仓库要单独放一块盘。这些都搞懂了,后面无论换新电脑还是接手新项目,都能用最快的速度把环境跑通。