ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Maven从入门到实践:安装配置与IDEA集成全攻略

Maven从入门到实践:安装配置与IDEA集成全攻略 新手学Java开发十有八九会撞到Maven这个名字。我在接手团队项目时经常碰到这样的场景同事代码逻辑写得没问题一打开IDEA就满屏红色提示找不到org.springframework、找不到junit。追问下去十次有八次是Maven没配好或者根本没有真正用上自己安装的Maven而是让IDEA用了内置的默认版本。这篇内容就把Maven从下载、安装、环境变量、仓库配置到IDEA集成的完整链路拆开讲一遍顺便把我这些年踩过的坑和排查思路都交代清楚。无论是第一次用Maven的新人还是经常跟依赖打架的老手都可以照着走一遍。1. Maven到底解决了什么问题它不只是个“下载工具”很多人对Maven的理解停留在“自动下载jar包”这个理解不算错但太片面。如果只是下载依赖那Gradle、Ivy也能做到甚至你用脚本去中央仓库拉压缩包也不是不行。Maven真正厉害的地方是把一套标准化的构建流程和依赖管理体系固化了下来。1.1 依赖管理与项目结构标准化在Maven之前Java项目的依赖管理是一场灾难。你需要去网上下载各种jar包手工拷贝到WEB-INF/lib目录然后手动加入classpath。不同版本之间的传递依赖比如A依赖BB依赖C完全靠人肉维护经常出现本地能跑、同事那里编译不了的情况。Maven用一个pom.xml文件描述项目需要哪些依赖它会自动解析依赖树把直接依赖和间接依赖都拉到本地仓库。同时Maven规定了标准的目录结构src/main/java - 主代码 src/main/resources - 配置文件 src/test/java - 测试代码 src/test/resources - 测试资源 target - 编译输出这个结构本身没有魔法但所有用Maven的项目都遵守同一套约定新人接手任何Maven工程都能快速定位代码。这就是“约定优于配置”的思想也是Maven长盛不衰的核心原因之一。1.2 构建生命周期从清理到发布Maven定义了一套完整生命周期clean、validate、compile、test、package、verify、install、deploy。每个阶段都是前一个阶段的自动前置比如你执行mvn install实际顺序是编译、跑测试、打包、安装到本地仓库一气呵成。在IDEA里你不需要敲命令右侧的Maven面板会展示这些生命周期节点点一下就行。但建议新手在命令行里跑一次完整的mvn clean package亲眼看到编译、测试、打包的过程输出这样你才能真正理解IDEA界面上那些按钮背后发生了什么。1.3 仓库的三个层级本地、中央、远程这是整篇文章的核心概念后面所有配置都围绕仓库展开本地仓库默认在用户目录下的.m2/repository所有下载过的依赖都会缓存到这里。本地已经存在的话离线也能编译。中央仓库Maven官方维护的公共仓库地址是repo.maven.apache.org绝大多数开源jar包都能在这里找到。远程私有仓库公司内部搭建的Nexus、Artifactory等存放内部公共库和对外下载的镜像缓存。一条依赖被解析时Maven的查找顺序是本地仓库 → 配置的远程仓库包含私服和中央仓库。搞清楚这个顺序很多配置问题就迎刃而解了。比如你明明配置了私服但本地包一直不更新很可能是本地仓库已经有旧版本Maven默认不会主动去远程仓库检查。2. 下载与版本取舍先看清JDK再决定Maven版本很多人在下载Maven时犯的第一个错误就是看到官网最新版本直接下载完全没考虑本机JDK版本能不能跟它匹配。版本不匹配的结果很直接IDEA导入项目后一堆奇怪的报错甚至mvn -v都跑不起来。2.1 Maven和JDK的版本对应关系这里有一张我维护项目时总结的对照表Maven版本最低JDK要求推荐JDK版本Maven 3.6.xJDK 1.7JDK 8、JDK 11Maven 3.8.xJDK 1.7JDK 8、JDK 11、JDK 17Maven 3.9.xJDK 8JDK 11、JDK 17Maven 4.0.xJDK 17JDK 17、JDK 21简单说如果你还在用JDK 8不要选Maven 4.x老老实实装3.8.x或3.9.x。如果你用的是JDK 17或21那3.9.x是当前最稳妥的选择。我的主力环境是JDK 17 Maven 3.9.6用了一年多没出过兼容性问题。先检查本机JDK版本再决定装哪个Mavenjava -version如果输出的是openjdk version 1.8.0_392那就用Maven 3.8.x。如果输出17.0.9可以放心用3.9.x。2.2 从官网下载注意bin和src的区别Maven官网下载页面地址是https://maven.apache.org/download.cgi进去之后你会看到一堆文件这里的关键是区分apache-maven-x.x.x-bin.zip/.tar.gz编译好的二进制包普通开发就下这个。apache-maven-x.x.x-src.zip/.tar.gz源代码包只有你想研究Maven内部实现才需要日常开发下载这个纯属浪费时间和磁盘空间。另外在Windows上推荐下载.zip格式在macOS或Linux上用.tar.gz解压命令分别是# Windows # 用压缩软件解压即可或者用 PowerShell Expand-Archive apache-maven-3.9.6-bin.zip -DestinationPath C:\apps # macOS / Linux tar -zxvf apache-maven-3.9.6-bin.tar.gz -C ~/tools提示解压路径不要带中文和空格。我见过同事把Maven解压到“C:\Program Files (x86)\临时工具”下面结果后面IDEA配置主目录时路径解析各种诡异问题。这个习惯从Java时代就流传下来JDK、Maven、Tomcat这类基础工具尽量放在纯英文无空格路径下能避免很多不必要的麻烦。2.3 下载后先看目录结构解压完先别急着配环境变量看一眼目录里有没有这几个关键内容bin/可执行脚本mvn和mvn.cmd都在这里conf/全局配置文件重点是settings.xmllib/Maven运行时依赖的jar包README.txt安装说明里面写明了对应的JDK要求其中conf/settings.xml是全局配置文件后面讲仓库配置时你要么改这个文件要么在~/.m2下创建一个用户级settings.xml来覆盖它。两者关系我先在这里埋个引子后面专门展开。3. 安装与环境变量把Maven装进系统而不是只让IDEA知道下载完Maven后需要在操作系统层面配置环境变量。这一步做对之后你才可以在命令行任意位置执行mvn命令IDEA也能通过系统环境找到Maven。很多教程只讲IDEA里配置一次就完事了但后续你如果要在CI服务器或Docker环境里复现构建环境变量的知识早晚要用到。3.1 Windows环境下配置假设Maven解压后的路径是C:\apps\apache-maven-3.9.6配置分两个阶段设置MAVEN_HOME右键“此电脑” → 属性 → 高级系统设置 → 环境变量。在系统变量中新建变量名MAVEN_HOME 变量值C:\apps\apache-maven-3.9.6注意变量值不要带末尾的反斜杠也不要填到bin目录这一级一定是指向Maven的根目录。修改PATH在系统变量里找到Path编辑并新增一行%MAVEN_HOME%\bin之所以用%MAVEN_HOME%而不是硬编码完整路径是为了以后升级Maven版本时只需要改MAVEN_HOME一个变量不用动PATH。配置完成后打开新的命令行窗口一定要新开旧窗口不会刷新环境变量执行mvn -v正常会输出类似这样的内容Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3fcfd13d9c3c5ae2) Maven home: C:\apps\apache-maven-3.9.6 Java version: 17.0.9, vendor: Eclipse Adoptium, runtime: ...这里有两个信息值得确认Maven home是否指向你刚解压的目录Java version是否是你预期的JDK。如果Java version显示的版本和java -version不一致说明JAVA_HOME环境变量可能没配对。Maven通过JAVA_HOME找到JDK而不是通过PATH里的java命令这一点很多人会误解。3.2 macOS / Linux环境配置在macOS上我习惯把Maven解压到~/tools目录下。先用文本编辑器打开shell配置文件# 如果你用的zsh vim ~/.zshrc # 如果你用的bash vim ~/.bash_profile在文件末尾添加export MAVEN_HOME$HOME/tools/apache-maven-3.9.6 export PATH$MAVEN_HOME/bin:$PATH保存后执行source ~/.zshrc mvn -v提示macOS用户不建议直接修改系统的/etc/paths文件虽然也能生效但每次系统升级都有被覆盖的风险。放在用户级配置里既安全又方便不同项目切换版本。3.3 为什么要区分全局配置和用户配置Maven安装目录下的conf/settings.xml是全局配置会影响这台机器上所有用户的Maven行为。而~/.m2/settings.xml是用户级配置只对当前用户生效。实际开发中我强烈建议使用用户级settings.xml原因很简单你升级Maven版本时新版本目录下的conf/settings.xml是全新的之前改的全局配置全部丢失。团队协作时每个人都用自己的用户级配置互不干扰也不会因为某个人改了全局配置导致别人构建异常。.m2目录通常放在用户目录下备份和迁移都方便。如果用户级文件不存在从Maven安装目录复制一份过去或者直接建一个空文件让IDEA自动生成都行。4. 仓库配置是重头戏本地仓库、中央仓库与国内镜像我敢说十个Maven问题里至少五个出在仓库配置上。要么是本地仓库路径被改得乱七八糟要么是下载依赖超时要么是公司私服地址配错了导致解析失败。这章把仓库这一块的配置彻底讲透。4.1 本地仓库路径默认够用吗本地仓库默认路径是~/.m2/repository对绝大多数人来说这个默认路径就够了。除非你的C盘空间很紧张或者你把.m2目录通过软链接放到了其他盘否则我并不建议新手把本地仓库改成D盘之类的位置。原因在于IDEA、命令行、各种构建脚本默认都会读取用户目录下的.m2如果你把localRepository改到自定义位置就必须确保所有工具都配了同一个settings.xml否则会出现IDEA里明明下载过依赖命令行里却重新下载一遍的尴尬情况。如果你确实想改就在settings.xml里写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/repository/localRepository /settings这段配置的意思是告诉Maven“把下载的jar包都放到D:/maven/repository目录下”。路径分隔符用正斜杠或者反斜杠在Maven里都能解析但建议写正斜杠兼容性更好。4.2 阿里云镜像配置国内开发者的实际选择Maven中央仓库服务器在国外国内网络环境下直接下载依赖经常慢到让人抓狂。这时候就需要配置镜像。镜像的本质是Maven本来要去中央仓库下载jar包你把流量引导到一个内容同步但延迟更低的地址。官方术语叫Mirror我习惯叫镜像或别名不要去纠结用词。下面是阿里云公共仓库的配置写在mirrors节点里mirrors mirror idaliyunmaven/id namealiyun public/name urlhttps://maven.aliyun.com/repository/public/url mirrorOfcentral/mirrorOf /mirror /mirrors解释一下关键字段id镜像的唯一标识随便起但不要和本地已有的id冲突。url镜像服务的实际地址。mirrorOf表示这个镜像拦截哪些仓库的请求。central表示只拦截Maven中央仓库*表示拦截所有远程仓库。注意mirrorOf这个配置很容易被人忽略但它恰恰是最重要的一个属性。如果你配置了多个镜像Maven会按照mirrors里的顺序从上到下查找第一个能匹配的就生效。所以要想让阿里云镜像生效mirrorOf要写central而不是*否则连公司私服的请求也会被阿里云接管那样私服里的内部依赖就拉不到了。阿里云镜像生效后Maven日志里的下载地址会变成https://maven.aliyun.com/repository/public/...。如果你看到日志里仍然访问repo.maven.apache.org那就说明镜像配置没生效检查一下settings.xml的文件位置和mirrorOf配置。4.3 配置多个镜像同一个依赖应该从哪里下载实际项目中你往往既需要访问阿里云镜像又需要访问公司内部私服。这个场景下不要偷懒合并成一个镜像而是分开配置并按需指定mirrorOfmirrors !-- 阿里云镜像 -- mirror idaliyunmaven/id namealiyun public/name urlhttps://maven.aliyun.com/repository/public/url mirrorOfcentral/mirrorOf /mirror !-- 公司内部私服 -- mirror idinternal/id nameinternal nexus/name urlhttp://nexus.company.com/repository/maven-public//url mirrorOfinternal-repo/mirrorOf /mirror /mirrors同时在pom.xml里需要声明你使用的是哪个仓库IDrepositories repository idinternal-repo/id urlhttp://nexus.company.com/repository/maven-public//url /repository /repositories这里的id要和mirrorOf里写的id对应。实际排查时很多问题就出在id对不上导致私服地址直接被忽略依赖解析失败报错又很隐晦不会提示id不匹配只会说找不到某个依赖。4.4 settings.xml里还有什么值得看的配置除了localRepository和mirrorssettings.xml里还有几个我日常会用到的节点servers配置访问私服或需要认证的镜像时需要使用的账号密码。注意这里保存的是server id对应的凭证如果泄露到公共仓库会有安全风险。profiles可以给不同环境激活不同配置。比如开发环境用阿里云生产构建用公司私服都可以通过profile来做。pluginGroups默认包含org.apache.maven.plugins如果公司有自定义插件组也需要追加在这里。这些配置不需要一次全部搞懂但你要知道它们存在。遇到“为什么这个依赖在我的环境能解析在别人环境就解析不了”这类问题时大概率是因为settings.xml的profile或pluginGroups配置不一致。5. IDEA集成的正确姿势主目录、配置文件与项目导入配好命令行里的Maven只是第一步真正高频的工作环境还是在IDEA里。很多新手在IDEA里导入Maven项目后一脸茫然有的项目自动解析了依赖有的项目怎么刷新都是灰色。区别往往就在IDEA识别到的Maven配置上。5.1 在IDEA里指定你安装的Maven版本打开IDEA进入Settings/Preferences路径是Build, Execution, Deployment - Build Tools - Maven这个页面上有三行关键配置Maven home path选择你本地安装的Maven根目录比如C:\apps\apache-maven-3.9.6。User settings file选择~/.m2/settings.xml。如果你没有用户级配置文件可以直接点击旁边的Override按钮再选择Maven安装目录下的conf/settings.xml。Local repository如果settings.xml里已经指定了localRepository这里会自动读取并显示不需要手动修改。提示IDEA默认会用它自行捆绑的Maven版本而不是系统环境变量里的那个。如果你希望IDEA的行为和命令行一致一定要在Maven home path里手动指向你安装的版本。否则可能出现“IDEA里能编译命令行里却报错”的诡异情况。另外在同一个设置页面往下翻你还会看到Runner选项卡这里有一个JRE设置。建议显式指定一个JDK版本避免IDEA自动切换到错误版本导致项目编译报错。5.2 首次导入Maven项目导入方式很简单File - Open选中项目根目录的pom.xmlIDEA会识别并提示这是一个Maven项目选择Open as Project即可。如果项目之前已经打开过但Maven依赖解析异常可以在IDEA右侧Maven面板里点击刷新按钮或者执行右键项目 - Maven - Reload projectReload操作会重新读取pom.xml解析新增的依赖并更新IDEA的依赖索引。5.3 Maven面板里到底有哪些按钮IDEA右侧工具栏找到Maven面板展开后你能看到这些结构Lifecycleclean、validate、compile、test、package、verify、install、deploy。Plugins项目里用到的Maven插件比如compiler-plugin、surefire-plugin。Dependencies当前项目的依赖树。日常开发中我最常用的是clean和package。改了代码后重新打包先执行clean清空旧的target目录再执行package重新编译打包这样能避免很多因为旧class文件残留导致的奇怪问题。如果你需要给某个模块单独打包可以先在IDEA左侧项目树里选中该模块的pom.xml再点Maven面板里对应的生命周期命令IDEA会自动把当前目录定位到该模块上。5.4 离线模式与自动导入IDEA的Maven设置里有一个Work offline选项默认是关闭的。有时候为了排除网络问题我会手动打开它测试本地依赖是否完整但平时一定记得关掉。还有一项Import Maven projects automatically默认开启后IDEA会在检测到pom.xml变化时自动重新导入。对大型多模块项目来说这个功能有时会频繁触发导致卡顿。如果项目特别大我更建议关掉自动导入手动执行Reload体验更可控。6. 依赖问题现场排查常见报错与我的处理流程这一章是实战经验我在各个项目里遇到过太多Maven依赖问题把这些高频问题的排查思路整理出来能帮你少走很多弯路。6.1 依赖一直处于Resolving状态进度条不动这是国内开发环境最频繁的问题。症状是IDEA导入项目后右侧Maven面板一直显示“Resolving dependencies...”但半天没有反应。排查顺序先确认网络是否能访问中央仓库或者是否已经配置了国内镜像。在命令行执行mvn clean compile -X-X参数会打印非常详细的调试日志重点看它访问的下载地址是repo.maven.apache.org还是maven.aliyun.com。如果地址是中央仓库且网络不正常那就说明镜像没生效检查settings.xml的mirrorOf。如果命令行下载没问题但IDEA卡住重启IDEA或者执行File - Invalidate Caches清理缓存后重试。6.2 上一次下载失败后重复下载仍然失败Maven下载依赖失败后会在本地仓库生成一个.lastUpdated后缀的文件这个文件会“记住”上次失败的状态。后续构建时Maven发现本地已经有这个记录会直接跳过下载导致你反复看到同一个报错。处理方式有两种。一是强制更新mvn clean install -U-U参数强制检查远程仓库更新忽略.lastUpdated文件。二是直接删除失败记录然后再重新构建find ~/.m2/repository -name *.lastUpdated -delete在Windows上可以打开本地仓库目录搜索.lastUpdated后缀文件手动删除。删除之后重新Reload项目基本都能解决。6.3 IDEA报错提示某个类找不到但pom.xml看起来没问题这种情况很有迷惑性。我的排查经验是先在Maven面板里看Dependencies树确认这个依赖是否真的被解析进来了。如果依赖树里有对应依赖但IDEA仍报错大概率是IDEA的缓存问题。执行以下操作通常能解决File - Invalidate Caches - Invalidate and Restart如果依赖树里根本没有这个依赖那就要检查两点一是pom.xml里的依赖坐标是否写对groupId、artifactId、version缺一不可二是这个依赖是否在某个父POM中被scope限制成了provided或test导致主代码里访问不到。还有一个容易忽略的原因多模块项目中A模块依赖B模块B模块的代码更新了但IDEA还在使用本地仓库里缓存的旧B模块jar包。这时需要在B模块上执行mvn install把最新版本安装到本地仓库A模块再重新Reload才能拿到新代码。6.4 本地仓库里明明有jar包Maven却还是去远程下载这个问题的根源是pom.xml里声明的版本不可变。Maven依赖解析遵循“版本固定优先于本地已有”的原则。如果你在pom.xml里写的是1.0-SNAPSHOTMaven会倾向检查远程仓库获取最新快照。如果是正式版本号1.0本地存在就直接使用不会反复下载。遇到这种问题先用-X看日志确认Maven到底在找哪个仓库的哪个版本然后决定是改pom.xml还是更新本地仓库。6.5 依赖版本冲突谁在背后覆盖了我的版本大型项目里依赖冲突防不胜防。A依赖被B和C同时依赖但B依赖1.0版本C依赖2.0版本最终生效的版本取决于依赖树中的声明顺序这往往不是你预期的那个。排查冲突的利器是依赖树命令mvn dependency:tree输出会让你清楚地看到每个依赖在树中的位置。想查看特定传递依赖是从哪里引入的加一个-Dincludes过滤mvn dependency:tree -Dincludescom.google.guava:guava确定冲突来源后可以在pom.xml里使用exclusions排除掉不想要的传递依赖dependency groupIdcom.example/groupId artifactIdsome-lib/artifactId version1.2/version exclusions exclusion groupIdcom.google.guava/groupId artifactIdguava/artifactId /exclusion /exclusions /dependency这段配置的含义是引入some-lib时不携带它的guava依赖避免和主项目里已有的guava版本冲突。7. 日常开发中几个提升效率的习惯Maven配好之后不是一劳永逸的日常工作中有几个习惯我觉得很值得养成。7.1 使用Maven Wrapper固定项目构建版本Maven Wrapper是一个脚本和配置的组合在项目根目录下放着mvnw和mvnw.cmd以及.mvn/wrapper/maven-wrapper.properties。它会把Maven版本固定在项目级别任何人拉取代码后执行./mvnw clean package都会自动下载并使用指定版本的Maven构建。这样团队内不会出现有人用3.6、有人用3.9导致的构建结果不一致问题。尤其在CI流水线上指定了Maven版本能大幅度减少环境差异类问题。首次使用可以执行mvn wrapper:wrapper -Dmaven3.9.6之后项目里就会生成wrapper文件提交到Git仓库即可。7.2 借助IDEA的Run Configuration配置Maven命令有些操作在Maven面板里找起来麻烦比如执行dependency:tree或者带参数的命令。我习惯创建一个Maven类型的Run Configuration命令直接写在里面Goalclean install -DskipTestsWorking directory当前模块路径VM options-Xmx1024m这样一键运行比在终端里切目录敲命令更快也不会打断IDE操作。7.3 不要手动修改本地仓库里的jar包很多人碰到依赖里的某个类行为异常时会手动去~/.m2/repository里找到对应jar包解压改class再塞回去试图绕过重新构建。这是大忌。首先Maven的校验机制会基于本地仓库元数据判断文件状态手动改过的jar包在后续构建中可能被强制覆盖你的修改等于白做。其次一旦本地仓库被污染排查问题的思路会被带偏你可能花费大量时间去查一个压根不存在的构建问题。正确的做法是修改源码重新执行mvn install把新版本安装到本地仓库。7.4 定期维护settings.xml的备份再分享一个小技巧我习惯把配好的settings.xml在本地保存一份副本命名成settings-backup.xml。每次升级Maven版本或者换新电脑时直接复制文件过去改个名就能用不用重新写配置。如果你换了新电脑旧机器上的settings.xml是你最该迁移的文件之一它的重要性甚至超过IDEA的配置。最后还想说一句Maven的配置看起来琐碎但本质上就是“仓库路径、镜像地址、IDEA识别”这三件事。这三件事理顺了日常开发里的依赖问题至少能解决八成。遇到报错时别急着搜问题先在命令行里执行一次带-X参数的命令看看它到底访问了哪个仓库、找什么依赖这个信息比任何博客里的经验贴都有用。
返回列表