一篇从「Maven 是什么」到「它如何与 IntelliJ IDEA 协作」的完整教学文档。结合官方文档与社区实践整理,适合需要彻底搞懂构建体系的 Java 开发者。
目录
- [Maven 在 Java 体系中的角色](#Maven 在 Java 体系中的角色)
- [Maven 核心概念:POM、坐标、仓库](#Maven 核心概念:POM、坐标、仓库)
- [Maven 的构建生命周期](#Maven 的构建生命周期)
- [依赖管理:Maven 最不可替代的价值](#依赖管理:Maven 最不可替代的价值)
- 标准目录结构
- [IntelliJ IDEA 与 Maven 是如何协作的](#IntelliJ IDEA 与 Maven 是如何协作的)
- [关键开关:Delegate IDE build/run actions to Maven](#关键开关:Delegate IDE build/run actions to Maven)
- 两套构建系统并存带来的坑(及规避)
- 常用命令速查
一、Maven 在 Java 体系中的角色
Apache Maven 是 Java 生态里最主流的构建管理与依赖管理工具 ,由 Apache 软件基金会维护,是 Java 开发的基石性工具What is Apache Maven? Build and dependency management for Java。
需要先建立一个关键认知:Maven 是一个独立于任何 IDE 的工具 。它脱离 IntelliJ、Eclipse、VSCode 都能单独运行------只要装了 Maven,命令行敲 mvn 就能用。IDE 只是「集成」并「调用」它。
Maven 主要承担两大职能:依赖管理 和 构建自动化 ELI5 - Maven。它基于 「约定优于配置」(convention over configuration) 的理念运作,通过统一的标准减少手工配置,从编译、测试一直管到打包和部署What is maven in devops?。
Maven 的核心价值可以概括为:
- 统一的构建方式 ------任何一个 Maven 项目,构建命令都一样(
mvn package),换个项目也不用重新学。 - 清晰的项目定义 ------
pom.xml一眼就能看出项目依赖什么、怎么构建。 - 依赖共享与传递------自动从中央仓库下载并管理第三方库及其传递依赖。
- 标准化项目结构 ------
src/main/java、target/这套约定就是 Maven 定的。
二、Maven 核心概念:POM、坐标、仓库
2.1 POM(Project Object Model)
每个使用 Maven 的项目,根目录下都有一个 POM 文件 pom.xml ,它描述了项目的依赖并告诉 Maven 如何构建项目What is Apache Maven?。POM 是 Maven 的「项目说明书」,是整个项目配置的唯一真相来源(single source of truth)。
一个最小的 POM 必须配置三个要素:groupId、artifactId 和 versionIntroduction to the POM - Apache Maven。
xml
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<!-- 项目坐标:唯一标识一个构件 -->
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<!-- 依赖声明 -->
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.2 坐标(Coordinates)
Maven 用一组「坐标」唯一定位一个构件,构件(artifact)正是由 Group ID 和 Artifact ID 的组合来标识,并可被其它项目当作依赖引用Maven Project: A Guide for Beginners:
| 坐标元素 | 含义 | 示例 |
|---|---|---|
groupId |
组织/团队的唯一标识,通常是倒置域名 | org.springframework |
artifactId |
项目/模块名 | spring-core |
version |
版本号(含 -SNAPSHOT 表示开发中版本) |
6.1.0 |
packaging |
打包类型 | jar / war / pom |
2.3 仓库(Repository)
当你在项目里声明一个依赖时,Maven 会在中央仓库中找到它,下载到本地仓库,再供项目使用What is Apache Maven?。
- 中央仓库(Central Repository):Maven 官方的公共仓库,绝大多数开源库都在这里。
- 本地仓库(Local Repository) :默认在
~/.m2/repository,下载过的依赖缓存在此,避免重复下载。 - 私有/远程仓库(Private Repository):企业内部的 Nexus / Artifactory 等,用于存放内部构件。
三、Maven 的构建生命周期
Maven 有三套内置生命周期:default(默认/构建) 、clean(清理) 和 site(站点文档) 。其中 default 生命周期负责项目的构建与部署,clean 生命周期负责清理Maven Tutorials: Maven Lifecycle, Phases \& Goal。
3.1 default 生命周期的 7 个核心阶段(Phase)
default 生命周期实际包含约 23 个阶段,但下面 7 个是最该掌握的Maven Build Phases and Commands - GeeksforGeeks:
| 阶段 | 作用 |
|---|---|
validate |
校验项目是否正确、必要信息是否齐全 |
compile |
编译 src/main/java 下的源码 |
test |
用 src/test/java 下的单元测试运行测试 |
package |
把编译结果打包成 jar / war |
verify |
对集成测试结果做校验,检查质量 |
install |
把打好的包安装到本地仓库,供本机其它项目依赖 |
deploy |
把包发布到远程仓库,供团队共享 |
3.2 关键规则:阶段是「累积执行」的
阶段是有顺序的,当你执行某个阶段时,Maven 会自动按顺序先执行它之前的所有阶段 What are Maven goals and phases。
例如运行 mvn install,Maven 会自动先跑 validate、compile、test、package、verify,最后才 installMaven Build Phases and Commands。
mvn install
└─ validate → compile → test → package → verify → install (全部自动按序执行)
3.3 Phase 与 Goal 的区别
- Phase(阶段):生命周期里的一个有序步骤,本身是个「容器」。
- Goal(目标) :插件提供的具体「动作」。在 Maven 里,「动词」是打包在插件中的 goal,它们被绑定到生命周期的某个 phase 上Chapter 4: The Build Lifecycle。
一句话:你告诉 Maven 跑某个 phase,Maven 就会执行绑定在该 phase 上的所有 goal。
3.4 clean 生命周期
clean 用于删除上一次构建产生的 target 目录,它包含 pre-clean、clean、post-clean 三个阶段;clean:clean 这个 goal 通过删除构建目录来清除构建输出Chapter 4: The Build Lifecycle。
实践中常把 clean 和构建命令连用,以保证用全新的 target 目录构建:
bash
mvn clean package # 先删 target,再重新打包
⚠️ 重要提醒 :
deploy在 Maven 语境里指「把构件发布到远程 Maven 仓库供他人依赖」,不是指「把应用部署到服务器运行」。后者属于运维/CI-CD/容器层面的事,不在 Maven 标准生命周期的本意之内。
四、依赖管理:Maven 最不可替代的价值
Maven 是 Java 项目依赖管理事实上的标准工具Java Dependency Management with Maven。它解决了「手工下载 jar 包 + 手工解决版本冲突」这个痛点。
4.1 依赖作用域(scope)
通过 <scope> 控制依赖在哪个阶段可用:
| scope | 含义 |
|---|---|
compile(默认) |
编译、测试、运行全程可用 |
provided |
编译/测试可用,运行时由容器提供(如 Servlet API) |
runtime |
运行和测试时需要,编译时不需要(如 JDBC 驱动) |
test |
仅测试时可用(如 JUnit) |
4.2 传递依赖与 dependencyManagement
Maven 会自动处理传递依赖(你依赖 A,A 依赖 B,Maven 自动帮你引入 B)。
在多模块项目中,<dependencyManagement> 用于集中管理依赖版本 :它本身不会真正引入依赖,而是提供一个版本参考,简化子模块后续添加依赖的工作Understanding pom.xml in Maven。子模块从父 POM 继承配置,保证多模块项目的一致性What is maven in devops?。
五、标准目录结构
Maven 的「约定优于配置」最直观地体现在目录结构上:
my-app/
├── pom.xml ← 项目说明书
├── src/
│ ├── main/
│ │ ├── java/ ← 主源码(compile 阶段编译)
│ │ └── resources/ ← 主资源文件(配置、静态文件)
│ └── test/
│ ├── java/ ← 测试源码
│ └── resources/ ← 测试资源
└── target/ ← 构建产物(自动生成,可删)
└── classes/ ← 编译后的 .class 文件
target/是 Maven 的输出地盘,里面的内容都是自动生成的,可随时删除并重建。target/classes就是mvn compile写.class的默认位置。
六、IntelliJ IDEA 与 Maven 是如何协作的
这是本文档的核心。要点是:IntelliJ IDEA 自己有一套编译器和构建系统,Maven 是另一套------它们是两个独立的执行者。
| 对比项 | IntelliJ 内建构建 | Maven |
|---|---|---|
| 谁执行 | IDE 自己的 javac 封装 | 独立的 mvn 进程 |
| 配置来源 | .idea/ 里的项目设置 |
pom.xml |
| 默认输出目录 | out/ |
target/ |
| 触发方式 | Build → Build Project / 绿色运行键 | Maven 工具面板 / mvn 命令 |
| 速度 | 快,支持增量编译 | 较慢,但与命令行/CI 完全一致 |
6.1 导入:以 pom.xml 为准重建项目模型
当你把项目作为 Maven 项目导入 IntelliJ 后,IDEA 会读取 pom.xml ,据此自动把依赖、模块、内容根、JDK 版本、构建目标等同步进 IDE。pom.xml 是 IDEA 项目模型的权威来源。
你可以在 IntelliJ 中链接、忽略项目,并在 Maven 与 IDEA 项目之间同步变更Maven projects \| IntelliJ IDEA Documentation。当 pom.xml 改动后,需要点 Maven 工具窗口里的 Sync/Reload All Maven Projects 图标重新同步Maven projects \| IntelliJ IDEA Documentation。
6.2 Maven 工具窗口
IntelliJ 在右侧提供一个 Maven 工具面板 ,把生命周期阶段(clean / compile / test / package / install...)和插件 goal 以可视化方式列出来,点一下就相当于帮你拼好对应的 mvn 命令去执行。
6.3 日常 Build/Run 由谁干?取决于一个开关
默认情况下,你按 IDE 的 Build 按钮或绿色运行键时,用的是 IntelliJ 自己的编译器 (输出到 out/ 或你在 Project Structure 里配置的 Compiler output)。是否改为委托给 Maven,由下一节的开关决定。
七、关键开关:Delegate IDE build/run actions to Maven
7.1 在哪里
Settings/Preferences → Build, Execution, Deployment → Build Tools → Maven → Runner ,里面有个勾选框 Delegate IDE build/run actions to Maven :勾选它,就会通过 Maven 来 build、run 和 debug 代码Maven. Runner \| IntelliJ IDEA Documentation。
如果你希望 IntelliJ 严格按照 Maven POM 来内部构建项目,就启用这个选项Ask IntelliJ to follow a Maven POM to build the project internally。
7.2 勾选 vs 不勾选
| 不勾(默认) | 勾上(委托 Maven) | |
|---|---|---|
| 编译者 | IntelliJ 内建编译器 | Maven(跑 pom.xml 配置的插件) |
| 输出目录 | out/ |
target/ |
| 速度 | 快,增量编译,适合日常开发 | 慢一些,但结果与命令行/CI 一致 |
| 插件执行 | 部分插件(代码生成、注解处理)不一定触发 | pom.xml 里配的插件都会正常执行 |
7.3 什么时候该勾上
- 构建依赖 Maven 插件做"代码生成" ------比如 Protobuf/Thrift、注解处理器、企业内部脚手架插件等,会在
generate-sources阶段生成.java源码。IDEA 自己的编译器不会执行这些插件,会出现「命令行能跑、IDE 跑不起来」「找不到生成的类」。勾上后就和命令行一致了。 - 要求与 CI/命令行构建结果严格一致------排查「本地 IDE 没问题、CI 却挂了」这类差异时,勾上能消除两套构建系统的不一致。
- 想让 IDEA 统一只用
target/------避免out/与target/两套产物并存导致的混乱。
这个开关在 WSL2 等环境下,也常被用来修复「Maven 项目找不到 imports / 无法运行」的问题Use Maven to Build and run your project in IntelliJ IDEA。
7.4 代价
勾上后每次都走完整的 Maven 流程,编译/运行变慢、失去增量编译优势。因此多数人的折中做法是:平时不勾(享受快速增量编译),只在遇到「IDE 与命令行不一致 / 插件没生效」时临时勾上验证。
八、两套构建系统并存带来的坑(及规避)
这是同时用 IntelliJ + 另一个工具(如 VSCode 的 JDT、或自定义 Maven 插件)时最容易踩的雷。
8.1 「Build 很快成功,却找不到主类」
如果点 Build 后日志里只有 Copying resources...、没有 Compiling ... java files,说明 IDEA 认为「没有 Java 源码需要编译」,只搬了资源就结束。常见原因:
- 源码目录没被标记为 Sources Root ------IDEA 只编译被标成 Sources(蓝色文件夹)的目录。结构被外部工具搞乱后,
src/main/java可能丢失该标记。 - 增量编译缓存陈旧 ------之前用
mvn clean或外部工具删了target,但 IDEA 缓存仍认为「已是最新」,于是跳过编译,但目录其实是空的。
排查/修复:
- 检查各模块
src/main/java在项目树里是否为蓝色 ;不是就在 Project Structure → Modules → Sources 中重新标记,或在 Maven 面板 Reload All Maven Projects 让其按pom.xml重建。 - 用 Build → Rebuild Project (而非 Build)强制全量重编,绕过缓存。正常会看到
Parsing java.../Writing classes...字样。
8.2 IDEA 与 Maven 共用同一个 target/classes,互相覆盖
IDEA 的 Compiler output 默认就指向 target/classes,而 Maven 的 compile 产物也是 target/classes------两套系统写同一个目录,会互相覆盖/清除 :mvn clean 会删掉 IDEA 编的 class;IDEA Rebuild 也会清掉重写。这就导致 target/classes 时空时满、增量缓存与实际产物对不上,进而「找不到主类」。
两个稳定方案(二选一):
- 方案一(推荐):统一走 Maven。勾上 Delegate IDE build/run actions to Maven,让编译、代码生成、输出全部由 Maven 一次性完整完成,不再有两套系统交替「半编译」的问题。
- 方案二:保持各自编,但养成习惯 。跑过
mvn clean或用过别的工具后,回 IDEA 先 Rebuild Project 再运行(别直接点运行,避免增量 Build 跳过编译);尽量不让两个 IDE 同时对同一项目做构建。
8.3 多 IDE 混用时的隔离建议
- 给两个工具配置不同输出目录,互不干扰。
- 把构建产物加入
.gitignore:target/、out/、build/、.classpath、.project、.settings/等。 - 最省心:同一项目尽量只用一个 IDE 主力构建,另一个只读不构建。
九、常用命令速查
bash
# 清理上次构建产物
mvn clean
# 编译主源码(产物到 target/classes)
mvn compile
# 运行单元测试
mvn test
# 打包成 jar/war(产物到 target/)
mvn package
# 先清理再打包(最常用的稳妥组合)
mvn clean package
# 安装到本地仓库 ~/.m2,供本机其它项目依赖
mvn install
# 发布到远程仓库,供团队共享
mvn deploy
# 跳过测试打包
mvn clean package -DskipTests
# 以 debug 模式输出详细日志
mvn clean install -X
总结
- Maven 是独立于 IDE 的依赖管理 + 构建工具 ,
pom.xml是它的配置核心,target/是它的产物目录。 - IntelliJ IDEA 的角色是把 Maven 集成进来、可视化调用它 ,并以
pom.xml为项目模型的权威来源;但 IDEA 自带的编译/构建与 Maven 是两套并存的系统。 Delegate IDE build/run actions to Maven这个开关决定 Build/Run 到底用 IDEA 编译器还是委托 Maven------对依赖代码生成插件的项目,勾上它能一劳永逸地避免「找不到类」。- 多套构建系统共用
target/classes时容易互相覆盖,遇到「Build 成功却跑不起来」时,第一反应用 Rebuild Project,根治则统一走 Maven。