Maven从0到1:依赖管理、仓库配置与构建实战详解
1. 从零理解Maven它不是“又是一个要装的工具”先不谈配置不谈命令我们聊聊 Maven 在你日常开发里到底扮演什么角色。你肯定遇到过这种情况项目里要引入一个 JSON 库你得先去官网下载 jar 包拷进项目再手动加到 classpath如果这个库还依赖别的库你还得把传递依赖一个个找齐。运气好碰上有文档的运气不好就靠搜索引擎一篇篇翻折腾半天才能编译通过。这还只是单机开发如果是团队协作每个人下的依赖版本都不一样A 用 2.0B 用 3.1C 就莫名其妙编译报错——这种问题我见得太多太多了。Maven 解决的就是这几件事依赖管理、构建标准化和项目生命周期管理。你只需要在一个叫pom.xml的文件里声明要用什么库、什么版本Maven 自己去仓库里下载把所有传递依赖一并搞定你也不需要记住javac、jar、cp这一串手动指令只需要执行mvn clean package它就把编译、测试、打包、生成报告全部做完。说得直白点Maven 就是一个“项目管家”从你新建项目的那一刻起它告诉你目录怎么建、依赖怎么加、构建怎么跑、产物在哪全流程标准化。这篇文章适合谁刚接触 Maven 的新人从零搭环境、配仓库、跑通第一个构建也适合用了很久但一直只是“idea 里点一下刷新”的开发者搞清楚配置文件里那些参数到底是什么意思、依赖报错怎么排查、多个仓库之间怎么切换。有些内容属于“平时用不到遇到问题才后悔没看”的偏门技巧我尽量都用大白话讲清楚跟着操作一遍基本能落地。我最早用 Maven 也是稀里糊涂pom.xml 全靠复制粘贴settings.xml 出了问题就上网搜搜到啥改啥越改越乱。所以这篇笔记我从头捋一遍把原理、配置、命令、避坑点放一起当成一个完整的入门手册来写。2. 核心概念先搞懂POM、坐标、仓库、生命周期2.1 POM整个项目的“总控文件”每个 Maven 项目根目录下都有一个pom.xml全称 Project Object Model意思是“项目对象模型”。它定义了项目的基本信息、依赖、插件、构建配置。可以说Maven 一切行为的起点都是这个文件没有它Maven 根本不知道从哪下手。一个最简单的 pom.xml 长这样project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion groupIdcom.example/groupId artifactIddemo-project/artifactId version1.0.0/version packagingjar/packaging /project解释几个关键标签groupId组织的唯一标识一般是公司域名反写比如com.example。artifactId项目本身的名称比如demo-project。version项目版本号开发中常用1.0-SNAPSHOT表示快照版本。packaging打包方式常见jar、war、pom。如果是聚合工程父工程打包方式就是pom。这四项合起来就是 Maven 中的“坐标”。任何构件在仓库里都有一个独一无二的坐标Maven 通过坐标定位并下载对应的 jar 包。2.2 仓库机制本地仓库、中央仓库、私服到底谁先谁后Maven 找依赖的顺序是固定的这个顺序非常影响你对“依赖报错”的排查。第一站是本地仓库。默认路径在用户目录下的.m2/repository比如 Windows 上是C:\Users\你的用户名\.m2\repositorymacOS/Linux 是~/.m2/repository。依赖第一次从远程下载后会缓存到这里下次直接从本地读取不联网也能编译前提是依赖都齐了。第二站是中央仓库。这是 Maven 官方的公共仓库地址是https://repo.maven.apache.org/maven2/里边几乎什么库都有但服务器在国外国内访问速度不稳定。这也就是为什么我们要配阿里云镜像——本质是用国内服务器做中转下载速度快很多。第三站是私服可选。公司内部往往有 Nexus 或 Artifactory 搭的私服用来存放私有 jar 包也能代理中央仓库。如果你在settings.xml里配置了私服Maven 会优先从私服拉取。“我有两个本地仓库怎么合并”这个问题之所以会出现就是因为本地仓库默认只有一个但有的人电脑上改了settings.xml中的 localRepository 路径或者换了台电脑拷贝了另一个仓库目录导致依赖分散在两个地方编译时这个从默认仓库找、那个从自定义仓库找麻烦得很。2.3 生命周期clean、install、package 这些命令到底做了什么Maven 有三套生命周期分别是clean、default默认、site。我们日常用的命令都是基于这三套来的。clean清理删掉target目录下的编译产物。default核心生命周期按顺序执行 validate → compile → test → package → verify → install → deploy。site生成项目站点文档用得少。关键点在于你执行mvn package时它会按顺序把 package 之前的所有阶段都执行一遍包括 compile、test并不是只打个包就完事。同理mvn install会执行到 install意味着先编译、测试、打包再把 jar 装进本地仓库。所以团队里联调时本地模块有改动必须先install别人才能拉到你的最新版本。注意如果你只想跳过测试进行打包可以用mvn package -DskipTests这个-DskipTests是跳过测试编译和执行通常在临时验证构建产物时用。3. 环境准备与配置从下载到跑通第一个命令3.1 下载安装与 JDK 版本对应关系Maven 本身是 Java 写的运行它需要 JDK。版本对应关系这个必须提前确认好不然 Maven 装完启动时报错你会一头雾水。直接给结论Maven 版本最低 JDK 版本说明Maven 3.3JDK 1.7老项目偶尔碰到Maven 3.6JDK 1.8目前最主流兼容 8/11/17Maven 3.8JDK 1.8同上Maven 3.9.xJDK 1.8可以跑在 8、11、17、21 上Maven 4.xJDK 1.8 以上新版本建议搭配 17 使用推荐新手直接下载 Maven 3.9.x 或 3.8.x搭配 JDK 8 或 JDK 17。别图新下载 4.x教程少插件兼容性还有坑没必要。下载地址用官方链接https://maven.apache.org/download.cgi进去找 “Files” 栏目下载apache-maven-3.9.x-bin.tar.gzmacOS/Linux或apache-maven-3.9.x-bin.zipWindows。如果官网下载慢可以考虑国内镜像站点下载但要注意校验文件完整性直接用压缩包解压就行。3.2 环境变量配置Windows、macOS、Linux 各来一遍这一步的目标很简单让你在命令行任意路径输入mvn -v都能看到版本信息。Windows 上的操作解压 Maven 到一个固定目录比如D:\dev\apache-maven-3.9.9避免路径里有中文和空格。右键“此电脑” → 属性 → 高级系统设置 → 环境变量。新建系统变量MAVEN_HOME值为 Maven 解压路径。编辑Path变量新增一行%MAVEN_HOME%\bin。打开新命令行窗口输入mvn -v验证。macOS 上推荐用 Homebrew一条命令搞定brew install maven装完检查一下/opt/homebrew/bin是否在 PATH 里输入mvn -v即可。如果非要手动安装下载解压后编辑~/.zshrc添加如下两行export MAVEN_HOME/Users/你的用户名/app/apache-maven-3.9.9 export PATH$MAVEN_HOME/bin:$PATH然后执行source ~/.zshrc。Linux以 CentOS/Ubuntu 为例# 下载解压 tar -xzf apache-maven-3.9.9-bin.tar.gz -C /opt/ # 编辑 /etc/profile 或 ~/.bashrc export MAVEN_HOME/opt/apache-maven-3.9.9 export PATH$MAVEN_HOME/bin:$PATH执行source /etc/profile后验证。配置完环境变量最典型的报错是mvn: command not found十有八九是 PATH 没加对或者没开新终端。另外一个坑Windows 上如果你之前装过 Maven 的其他版本环境变量里的 Path 可能有冲突优先检查MAVEN_HOME是否指向了你想要的那个版本。3.3 验证安装mvn -v 输出怎么看输入mvn -v正常输出类似Apache Maven 3.9.9 (8e3f3e0d2e7f0b4e0d4f6f1e1a0e1f2e3f4e5f6) Maven home: /opt/apache-maven-3.9.9 Java version: 17.0.5, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-17 Default locale: zh_CN, platform encoding: UTF-8 OS name: linux, version: 5.15.0, arch: amd64, family: unix看三行Maven home 是否正确Java version 是否是你要的版本platform encoding 是不是 UTF-8。如果 Java 版本不对说明你的 JAVA_HOME 配置有问题Maven 用的是JAVA_HOME环境变量指向的 JDK不是你命令行里的 java。这个细节容易踩坑尤其是电脑上装了多个 JDK 时。4. 配置国内可用的仓库settings.xml 与阿里云镜像实战4.1 settings.xml 到底在哪里改哪个Maven 有两套settings.xml全局配置在 Maven 解压目录下的conf/settings.xml影响这台电脑上所有用户、所有项目。用户配置在~/.m2/settings.xml只影响当前用户。如果两个都存在用户配置优先。一般建议改用户配置因为升级 Maven 时不会覆盖全局配置也不会影响别人。直接在~/.m2/下新建 settings.xml 内容复制全局配置再改即可。新手不知道改的是哪个文件的时候在命令行执行mvn help:effective-settings它会列出最终生效的配置文件路径和内容非常直观。4.2 配置阿里云镜像三步让下载速度起飞在国内用中央仓库下载依赖那个速度简直不能忍一个小 jar 等半天是常事。配置镜像就是给仓库访问换一个“就近入口”。在settings.xml的mirrors节点下加一段mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror核心是mirrorOf标签它表示这个镜像代理哪个远程仓库。central表示代理中央仓库。注意https://maven.aliyun.com/repository/public这个地址是阿里云提供的公共聚合仓库它包含中央仓库渠道和公共 JCenter 渠道覆盖绝大多数依赖。如果某些内部构件需要单独仓库后面会讲多镜像怎么配。修改完保存随便在项目里执行mvn clean compile你会看到日志里下载速度直接从几十 K 变成几 M。如果还是慢检查一下是不是镜像没生效——执行以下命令看 effective settingsmvn help:effective-settings确认 mirrors 节点里有没有阿里云配置。4.3 配置多个镜像仓库单个镜像满足不了项目需要时有些项目既需要中央仓库的公共依赖又需要公司私服里的内部构件。如果只配一个mirror且mirrorOf设为*会把所有请求都指过去万一这个镜像没有你要的依赖构建直接失败。正确的做法是配置多个 mirror并精确控制每个 mirror 代理的范围。举例公司私服地址是http://nexus.internal.com/repository/maven-public/你想让公共依赖走阿里云私服走公司内网。mirrors !-- 公司私服 -- mirror idinternal-nexus/id mirrorOfinternal-repo/mirrorOf name公司内网仓库/name urlhttp://nexus.internal.com/repository/maven-public//url /mirror !-- 阿里云镜像 -- mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror /mirrors然后在repositories节点里声明一个 id 为internal-repo的仓库repositories repository idinternal-repo/id urlhttp://nexus.internal.com/repository/maven-public//url releasesenabledtrue/enabled/releases snapshotsenabledtrue/enabled/snapshots /repository /repositories这样 Maven 遇到内部构件时会通过镜像走上内网仓库公共依赖走上阿里云。实际使用中公共依赖占多数阿里云仓库速度优势能充分利用而内部构建也不会因为阿里云上找不到而失败。4.4 修改本地仓库路径并合并多个 repository前面提到过“两个本地仓库怎么合并”的问题。这种场景有几种电脑上残留了旧仓库目录新仓库在默认路径。从同事那拷了一个 repository 目录里面有几个需要的 jar 但版本比较旧。以前手动改过 localRepository之后又忘了。最简单的处理是确定一个主仓库目录把另一个合并进去。因为 Maven 的本地仓库本质上就是“坐标 → jar 文件”的目录结构每个依赖都在类似com/example/demo-project/1.0.0/demo-project-1.0.0.jar这样的路径下。合并时把旧仓库中缺失的构件文件夹复制到主仓库即可。步骤先确定主仓库路径。如果默认在~/.m2/repository就让它当主仓库。打开命令行执行# 查看当前本地仓库路径 mvn help:evaluate -Dexpressionsettings.localRepository -q -DforceStdout如果输出null说明没改过配置用的默认路径如果输出具体路径说明之前改过。以主仓库为准需要合并的内容把两个目录做一次对比把旧仓库里主仓库没有的文件夹复制过去。复制时注意别把_remote.repositories和.lastUpdated这些元数据文件硬覆盖那些是 Maven 用来校验远程下载状态的搞乱了之后可能触发奇怪的“已存在但无法解析”的报错。拷贝完后再执行mvn dependency:resolve验证依赖是否都解析成功。这里必须提醒一点不用刻意让两个仓库“合二为一”。如果你的依赖分散在多个磁盘位置更优雅的做法是让本地仓库只留最新的一个其余通过配置repository或localRepository实现多路径加载——但说句实在话Maven 并不直接支持“本地仓库多路径”。它只认一个localRepository。所以想合并整理合并目录是最踏实的方案。5. 在 IDE 中集成 MavenIDEA 与 VSCode 的差异化配置5.1 IDEA核心配置只有三处IDEA 是 Java 开发最常用的 IDE配置 Maven 的路径是Settings → Build, Execution, Deployment → Build Tools → Maven。你需要改三个地方Maven home path选择 Maven 解压目录。IDEA 自带了一个 Maven有时会用自带版本执行构建建议手动指向你自己的 Maven。User settings file右边有 Override 复选框勾选后选择你的settings.xml。Local repositoryIDEA 会自动识别 settings.xml 里配置的本地仓库路径但如果你没改过 settings它会默认用自己的.m2/repository这里建议手动确认一下改成你想要的那个目录。如果你在 pom.xml 里加依赖后 IDEA 一直爆红大概率是没刷新。右侧 Maven 工具栏点一下刷新按钮或者用快捷键Ctrl Shift OWindows/Linux/Command Shift OmacOS。这个操作会重新解析依赖如果还是报错再看下面的依赖排查章节。还有个小技巧IDEA 的 Build 和 Maven 是两套体系。有时候 IDEA 自带编译器编译通过但命令行mvn clean package报错这是正常的因为 IDEA 内置编译器走的是它自己的依赖解析逻辑跟 Maven 不完全一致。最终以 Maven 的构建结果为准。5.2 VSCode插件组合了解一下VSCode 配置 Maven 没有 IDEA 那么集成化但它有一个比较轻量的套路。先装两个插件Extension Pack for Java微软官方和Maven for Java也是微软官方。前者管 Java 语言支持后者管 Maven 项目解析。VSCode 里 Maven 的配置其实走的是 settings.json{ java.configuration.maven.userSettings: /Users/你的用户名/.m2/settings.xml, java.configuration.maven.globalSettings: /path/to/global/settings.xml, maven.executable.path: /opt/apache-maven-3.9.9/bin/mvn }如果你发现 VSCode 加载项目时依赖解析很慢或者总提示“cannot resolve symbol”大概率是 VSCode 找不到 Maven 的可执行文件或 settings.xml 路径不对。帮 VSCode 明确指定后重启窗口即可。注意VSCode 修改配置后建议执行Java: Clean Java Language Server Workspace或者重载窗口否则语言服务可能缓存旧配置。5.3 IDE 配置 JDK 与 Maven 的常见坑很多新手在 IDEA 里配置 JDK 时只设置了 “Project SDK”但 Maven 用的是自己的 JDK 配置。在 IDEA 中Maven runner 的 JDK 和项目编译的 JDK 是两个维度。项目编译 JDKProject Structure → Project → SDKMaven 运行 JDKSettings → Build Tools → Maven → Runner → JRE如果发现 Maven 构建时用的版本不对优先检查 Runner 里的 JRE 选项。VSCode 中则通过java.configuration.runtimes配置java.configuration.runtimes: [ { name: JavaSE-17, path: /usr/lib/jvm/java-17, default: true } ]这个配置的意义在于Maven 编译插件如 compiler-plugin会读取 JAVA_HOME 环境变量或者 IDE 传入的 JDK 路径。如果环境变量和 IDE 内部的 JDK 不一致可能出现“编译报错 class file version 错误”。本质就是 JDK 版本冲突不要慌统一 JDK 版本后重新构建即可。6. 依赖管理进阶从依赖报错到多模块项目6.1 那些年我们一起踩过的依赖报错全在这了依赖报错是新手遇到最多的拦路虎。我把常见报错和对应排查方向整理成一个速查表报错信息可能原因排查方向Cannot resolve symbol依赖没下载完成 / IDEA 索引没刷新刷新 Maven 项目删.lastUpdated文件重新导入Could not find artifact com.xxx:xxx:1.0仓库里没有这个坐标/版本确认坐标是否写错检查私服或镜像是否包含该构件Unknown lifecycle phase install命令拼写错误或引号问题检查命令格式比如mvn clean install不要写成mvn clean-installConnection timed out仓库访问不了检查网络确认代理是否影响本地连接The forked VM terminated without properly saying goodbye测试进程内存溢出调整 surefire 插件 forkCount 和 argLine 参数Failed to execute goal ... compiler-plugin ... compilation failure编译失败打开完整报错输出定位到具体文件具体行invalid target release: 17JDK 版本和编译插件版本不匹配升级 compiler-plugin 到 3.8.0或在 pom 里指定 maven.compiler.source/target有一个经验性极强的排查技巧删掉本地仓库里.lastUpdated结尾的文件。这类文件表示之前下载失败Maven 会因为它们的存在而不再重新下载。执行删除后重新构建# Linux / macOS find ~/.m2/repository -name *.lastUpdated -exec rm -rf {} \; # WindowsPowerShell Get-ChildItem -Path $HOME\.m2\repository -Recurse -Filter *.lastUpdated | Remove-Item然后重新mvn clean install。这个操作能解决很大一部分“依赖明明存在但解析失败”的问题。6.2 依赖传递与排除依赖为什么 jar 包里多了一堆不认识的库Maven 的依赖是有传递性的比如你引入spring-boot-starter-web它自己又会引入 Tomcat、Spring MVC、Jackson 等几十个依赖。好处是省事坏处是版本冲突和冗余依赖难以控制。看当前项目的完整依赖树mvn dependency:tree这个输出非常有用它能显示每个依赖是怎么被引入的以及版本是什么。如果你发现某个传递依赖版本不对可以在 pom 里显式声明这个依赖的版本Maven 在依赖冲突时会优先选择 pom 中直接声明的版本“就近优先”原则。如果想排除某个传递依赖用exclusionsdependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId exclusions exclusion groupIdch.qos.logback/groupId artifactIdlogback-classic/artifactId /exclusion /exclusions /dependency排除依赖很有用尤其是在你不想用某个库的默认实现想替换成自己的实现时。但注意排除后必须自己补上替代依赖否则运行时会有ClassNotFoundException。6.3 多模块项目一个父 POM 管所有实际项目里很少只有一个模块。常见的结构是一个父工程加多个子模块my-project/ ├── pom.xml (父POM, packaging pom) ├── common/ (公共工具模块) ├── service/ (业务服务模块) └── web/ (接口模块)父 POM 关键部分packagingpom/packaging modules modulecommon/module moduleservice/module moduleweb/module /modules子模块只需要写自己的artifactId和依赖。如果子模块之间也有依赖关系比如 web 依赖 service直接在 web 的 pom 里加上 service 的依赖即可dependency groupIdcom.example/groupId artifactIdservice/artifactId version1.0-SNAPSHOT/version /dependency这种情况下开发顺序有讲究。你改了 common 模块必须先在 common 目录下执行mvn clean install把新版本装进本地仓库然后再去构建 service 或 web否则它们会用到旧版本。如果改了代码但构建时老是用旧版本优先检查你是不是忘了 install 依赖模块。6.4 依赖版本统一管理properties 和 dependencyManagement很多项目里会出现十几个依赖都是version标签里写死 1.0 的情况升级时逐处改改到一半忘了改另一个然后就冲突了。更优雅的做法是这样的在父 POM 中定义 propertiesproperties spring.version5.3.20/spring.version jackson.version2.13.4/jackson.version /properties子模块引用dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version${spring.version}/version /dependency另外推荐使用dependencyManagement统一控制依赖版本。它和 dependencies 的区别是dependencyManagement 只在父 POM 中管理版本号子模块声明依赖时可以省略 version系统会自动继承。如果子模块想覆盖自己写上 version 即可。这个模式在多模块项目里是标准做法强烈建议养成就这样写。7. 常用命令与打包细节clean、install、package 的进阶用法7.1 命令速查表与执行顺序日常开发中几个高频命令命令作用实际场景mvn clean清理 target 目录重新构建前先把旧产物删掉mvn compile编译主代码快速检查代码能否编译通过mvn test运行单元测试验证测试用例mvn package打包成 jar/war输出构建产物mvn install打包并安装到本地仓库供其他模块或项目依赖mvn deploy上传到私服发布版本给团队使用mvn dependency:tree查看依赖树排查依赖冲突和传递依赖mvn help:effective-pom查看最终生效的 POM了解默认配置命令行里mvn clean install是比较常见的组合写法它先执行 clean 生命周期再执行 default 生命周期到 install 阶段。注意顺序不是install clean一定把clean放前面。7.2 跳过测试的正确姿势别再乱写了跳过测试有几种方式参数不同效果也不同-DskipTests编译测试类但不执行测试。适合需要快速验证构建产物的场景。-Dmaven.test.skiptrue不编译也不执行测试类。场景是确定测试代码没必要编译的情况比如改了主代码但测试代码暂时坏了。如果项目里集成测试特别耗时只是临时本地打包你想跑快一点mvn clean package -DskipTests就够用了。但发布到公司流水线上的话通常不应该跳测试避免把坏代码发上去。有些项目配置了maven-surefire-plugin的skipTests属性它在 pom 里也会起作用plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-surefire-plugin/artifactId configuration skipTestsfalse/skipTests /configuration /plugin优先级是命令行参数 pom 配置 默认值。如果你的 pom 里写死了 skipTeststrue命令行加-DskipTestsfalse是覆写不回来的。这是因为 IF 条件的原因跳过测试的开关比较特殊。遇到这种坑直接改 pom 或者用-Dmaven.test.skipfalse试试。7.3 打包命名finalName 和 classifier 的使用默认打包产物是artifactId-version.jar比如demo-project-1.0.0.jar。如果想自定义文件名在 pom 里加build finalNamemy-demo/finalName /build如果同一个项目想生成不同场景的包用 classifier。比如同时输出jar和jar-with-dependencies包含所有依赖的可执行 jar就得借助插件配置。典型用法是配置 maven-assembly-pluginplugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-assembly-plugin/artifactId configuration descriptorRefs descriptorRefjar-with-dependencies/descriptorRef /descriptorRefs finalNamemy-demo/finalName appendAssemblyIdfalse/appendAssemblyId /configuration /pluginappendAssemblyIdfalse会让生成的 jar 不带-jar-with-dependencies后缀直接以 finalName 命名。这个设置有时候很实用特别是别人要求一个固定名字的交付物时。8. 基于实际场景的演练从零构建一个小项目8.1 用命令创建 Maven 项目骨架用 Maven 命令行创建项目mvn archetype:generate -DgroupIdcom.example \ -DartifactIdhello-maven \ -DarchetypeArtifactIdmaven-archetype-quickstart \ -DinteractiveModefalse执行完成后会生成一个包含pom.xml和App.java的基础 Java 项目的骨架。注意这个 archetype 生成的版本比较旧编译时如果你用 JDK 17可能需要手动在 pom 里升级编译器插件版本否则会报source/target 1.5 已过时或invalid target release的错误。推荐一个更现代的创建方式直接用 Spring Initializr网页版生成项目后导入 IDEA或者用 IDEA 的“New Project”向导选择 Maven 模板。IDEA 2022 之后默认支持 Spring Boot 项目的 Maven 结构初始化生成的 pom 基本可用省去手动调整编译参数的步骤。8.2 添加依赖并构建验证在生成的pom.xml中添加一个实际依赖比如commons-lang3dependency groupIdorg.apache.commons/groupId artifactIdcommons-lang3/artifactId version3.14.0/version /dependency在App.java中写一段代码package com.example; import org.apache.commons.lang3.StringUtils; public class App { public static void main(String[] args) { System.out.println(StringUtils.capitalize(hello maven)); } }然后依次执行mvn clean compile mvn exec:java -Dexec.mainClasscom.example.App如果 exec 插件没有配置可以用mvn package后通过java -cp target/classes:依赖路径 com.example.App运行。更直接的方式是在 IDEA 中右键运行 App.main 方法这就不依赖 Maven 插件了。8.3 将模块发布到本地仓库供其他项目复用假设hello-maven是一个公共工具模块另一个web-demo项目要依赖它。在hello-maven目录下执行mvn clean install然后到web-demo的 pom 里加依赖dependency groupIdcom.example/groupId artifactIdhello-maven/artifactId version1.0-SNAPSHOT/version /dependencyinstall和package的区别就在这里package只是生成 jar 到 target本地仓库里还是旧版本install会将新的 jar 安装到本地仓库的坐标目录下。这就是为什么多人协作时必须 commit 后统一执行 install而不只是 package。我记得有一次项目组里有人只改了代码没 install另一个人怎么拉代码都还是旧版本排查到凌晨才发现是这个问题。9. 常见问题与排查技巧实录9.1 Maven 官网下载慢、下载包损坏怎么破官网下载慢有两个思路一是找国内源下载二是用命令行下载。推荐一个比较稳的组合在官网找一个具体版本文件的完整 URL然后换镜像域名下载。比如官网地址是https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.tar.gz那你可以尝试用阿里云镜像的地址https://maven.aliyun.com/repository/central/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.tar.gz下载完成后校验 SHA-256。这个校验比“能解压”更靠谱解压出来损坏的文件经常导致很奇怪的构建错误。9.2 IDEA 中 Maven 依赖全部爆红两大类原因IDEA 中看着一堆红色的 import第一反应别急着改 pom。先分两类从未下载成功看本地仓库里是否有对应坐标目录是否只有.lastUpdated文件。已经下载成功但 IDEA 没识别刷新 Maven 项目甚至重启 IDEA。如果刷新没用执行mvn clean install -U-U会强制更新快照版本和远程元数据。这招对 SNAPSHOT 依赖特别有效因为 Maven 默认每天只检查一次快照更新-U可以绕过这个缓存策略。9.3 一个依赖反复下载失败.lastUpdated 的陷阱经常有这种情况某个 jar 第一次下载超时之后你再怎么刷新它都提示找不到。原因就是 Maven 生成了.lastUpdated文件作为“上次下载失败”的标记在同一个时间窗口内默认一天它不会重新尝试。除了删除这些标记文件外如果项目急用还可以在仓库管理端重新上传 jar或者直接把 jar 手动放进本地仓库的对应目录并在旁边建一个_remote.repositories文件。文件内容格式如下# NOTE: This is a Maven Resolver internal implementation file # It is not intended to be edited hello-maven-1.0-SNAPSHOT.jarcentral hello-maven-1.0-SNAPSHOT.pomcentral路径和文件名按照实际 jar 情况填写。这招适用于“我有 jar 包但仓库服务器暂时连不上”的应急情况。9.4 多个 Maven 版本共存不同项目用不同版本怎么办有的公司老项目锁定 Maven 3.6.x新项目用 3.9.x。如果只配置一个 MAVEN_HOME 全局变量切项目时总得改来改去。更实用的方案是用 SDKMANLinux/macOS或者直接用 IDEA/VSCode 的项目级 Maven 配置。IDEA 里每个项目可以单独指定 Maven home path不受全局影响。命令行用的就是全局变量。开发中一般不怎么在命令行频繁切版本所以直接在 IDE 里配置项目级 Maven 最省心。另外 Windows 上如果装了不止一个 Maven检查一下 Path 里有没有多个指向 Maven bin 的条目——有时候 IDEA 会自己配一个 Maven 路径覆盖了系统变量。这种情况不是 Bug是优先级问题习惯就好。9.5 配置了私服但依赖还是走中央仓库这种情况很常见原因是你的mirror配置和repository配置没配合好。Maven 解析仓库的优先级有几个阶段先去本地仓库找没有就向远程仓库请求。远程仓库的查找顺序受到 mirror 影响。如果 mirror 的 mirrorOf 配置为*所有远程仓库请求都会走这个镜像。所以当你配了一个mirrorOf*指向阿里云时私服相当于被“架空”了。要么改 mirrorOf 为external:*表示除本地文件之外的仓库都走这个镜像但本地仓库除外要么精确指定你想让镜子代理的仓库 id。external:*这种写法有个细节Maven 会认为“外部”仓库包含所有非 localhost 和非 file:// 的仓库。如果你私服是内网 IP它也会被代理到阿里云导致内网构件找不到。想兼顾还是得用多镜像并精确控制 mirrorOf 更靠谱。10. 最后分享一点实战体验写到这里该说的都说了。我在项目里折腾 Maven 的时间不算短遇到的最大问题永远是“凭直觉改配置”而不是“按原理排查”。Maven 的设计思路其实不复杂给每个构件一个坐标按坐标去仓库找找到就下载找不到就报错。你的 pom 和 settings 就是对这个过程的“路径规划”。如果你刚开始学我的建议很直接不要复制粘贴别人的完整配置就完事。先自己创建项目用默认配置跑通一次再逐步加上镜像、私服、多模块、统一版本管理。每次修改只改一个变量跑一次构建确认效果再改下一个。这个过程看起来慢但会让你真正理解每个配置的意义以后再遇到问题就知道去哪看、怎么排查。还有一个小习惯值得坚持养成看完整日志而不是只看报错摘要的习惯。Maven 报错信息里真正的原因往往在日志中段或末尾那些[ERROR]行下面跟着的“Caused by”才是问题的源头。比如依赖冲突时它会明确告诉你是哪个 jar、哪个版本、被哪条依赖链引入顺着排查基本十分钟内解决。Maven 这个工具本身并不难难的是“当你以为懂了之后遇到的那些奇怪问题”。但只要掌握了仓库机制、生命周期、配置优先级这几个核心大概率能应对日常开发中绝大多数场景了。