三大生命周期
Maven 生命周期是理解 Maven 构建流程的核心。很多开发者只知道执行 mvn package,但不理解为什么执行 package 会自动编译、测试。理解生命周期后,你就能精确控制构建流程,知道每个命令实际做了什么。
为什么需要生命周期
传统构建的困惑
没有标准化的构建流程,不同项目做法不同:
项目A的构建流程:
ant compile → ant test → ant jar → ant deploy
项目B的构建流程:
gradle build → gradle upload
项目C的构建流程:
手动运行脚本...谁知道做了什么
问题:
- 不同项目构建方式不同,新人上手困难
- 构建顺序不一致,容易遗漏步骤
- 没有标准,难以理解每个命令的含义
Maven 解决方案:标准化生命周期
Maven 定义了标准化的构建阶段,所有 Maven 项目遵循相同的构建流程:
标准流程:
validate → compile → test → package → install → deploy
所有 Maven 项目都是这个顺序,新人一看就懂
生命周期概览
Maven 定义了三个独立的生命周期:
┌─────────────────────┬─────────────────────┬─────────────────────┐
│ Clean 生命周期 │ Default 生命周期 │ Site 生命周期 │
│ 清理构建产物 │ 核心构建流程 │ 生成项目文档 │
├─────────────────────┼─────────────────────┼─────────────────────┤
│ pre-clean │ validate │ pre-site │
│ clean │ compile │ site │
│ post-clean │ test │ post-site │
│ │ package │ site-deploy │
│ │ install │ │
│ │ deploy │ │
└─────────────────────┴─────────────────────┴─────────────────────┘
三个生命周期互不影响,可以单独执行或组合执行。
Clean 生命周期
阶段顺序
| 阶段 | 说明 | 实际执行的任务 |
|---|---|---|
| pre-clean | 清理前的准备工作 | 自定义钩子(很少用) |
| clean | 清理构建产物 | 删除 target 目录 |
| post-clean | 清理后的处理工作 | 自定义钩子(很少用) |
执行命令
mvn clean
实际效果
执行前:
project/
├── src/
├── pom.xml
└── target/ ← 构建产物
├── classes/
├── test-classes/
└── my-app.jar
执行 mvn clean:
删除 target 目录
执行后:
project/
├── src/
└── pom.xml
target/ ← 被删除
为什么需要 clean
问题场景:
场景:修改了源码,但 target/classes 里还有旧的 class 文件
没有 clean:
mvn compile ← 增量编译,只编译修改的文件
← 但有时增量编译不准确,导致旧代码残留
← 运行时可能使用旧代码
有 clean:
mvn clean compile ← 先删除 target,再重新编译
← 确保所有代码重新编译
← 保证使用最新代码
什么时候需要 clean:
| 场景 | 是否需要 clean |
|---|---|
| 日常开发小改动 | 不需要(增量编译足够) |
| 切换分支后 | 需要(清理旧分支产物) |
| 发布构建 | 需要(确保完整构建) |
| 出现奇怪的编译问题 | 需要(重新编译解决) |
| CI/CD 构建 | 需要(每次干净构建) |
Default 生命周期
Default 生命周期是 Maven 的核心,定义了完整的项目构建流程。
完整阶段列表
Default 生命周期有很多阶段,但我们只需要关注核心阶段:
| 阶段 | 说明 | 绑定的插件目标 | 重要程度 |
|---|---|---|---|
| validate | 验证项目正确性 | 无 | 低 |
| initialize | 初始化构建状态 | 无 | 低 |
| generate-sources | 生成源码 | 自定义插件 | 中 |
| process-resources | 处理资源文件 | resources:resources | 中 |
| compile | 编译源码 | compiler:compile | ⭐⭐⭐ 高 |
| process-classes | 处理编译产物 | 无 | 低 |
| generate-test-sources | 生成测试源码 | 自定义插件 | 中 |
| process-test-resources | 处理测试资源 | resources:testResources | 中 |
| test-compile | 编译测试源码 | compiler:testCompile | ⭐⭐ 中 |
| test | 执行单元测试 | surefire:test | ⭐⭐⭐ 高 |
| prepare-package | 准备打包 | 无 | 低 |
| package | 打包 | jar:jar 或 war:war | ⭐⭐⭐ 高 |
| pre-integration-test | 集成测试前 | 自定义 | 低 |
| integration-test | 集成测试 | failsafe:integration-test | 中 |
| post-integration-test | 集成测试后 | 自定义 | 低 |
| verify | 验证构建产物 | 自定义 | 低 |
| install | 安装到本地仓库 | install:install | ⭐⭐⭐ 高 |
| deploy | 发布到远程仓库 | deploy:deploy | ⭐⭐ 高 |
核心阶段详解
compile 阶段
作用:编译 src/main/java 源码到 target/classes
输入:src/main/java/**/*.java
输出:target/classes/**/*.class
执行命令:mvn compile
实际执行:
1. 处理资源文件(process-resources)
2. 编译源码(compiler:compile)
test 阶段
作用:执行 src/test/java 测试代码
输入:src/test/java/**/*Test.java
输出:target/surefire-reports/测试报告
执行命令:mvn test
实际执行:
1. 编译源码
2. 编译测试源码(test-compile)
3. 执行测试(surefire:test)
package 阶段
作用:打包项目为 jar 或 war
输入:target/classes(编译产物)
输出:target/my-app-1.0.0.jar 或 .war
执行命令:mvn package
实际执行:
1. 编译
2. 测试
3. 打包(jar:jar 或 war:war)
install 阶段
作用:将构件安装到本地仓库,供其他项目引用
输入:target/my-app-1.0.0.jar
输出:~/.m2/repository/com/example/my-app/1.0.0/
执行命令:mvn install
实际执行:
1. 编译 → 测试 → 打包
2. 安装到本地仓库(install:install)
实际用途:多模块项目中,模块 A 需要依赖模块 B,先对 B 执行 install,A 才能引用 B。
deploy 阶段
作用:将构件发布到远程仓库,供团队共享
输入:target/my-app-1.0.0.jar
输出:远程仓库
执行命令:mvn deploy
实际执行:
1. 编译 → 测试 → 打包 → install
2. 发布到远程仓库(deploy:deploy)
实际用途:发布新版本供团队成员或其他项目使用。
阶段触发规则—— 核心
执行某个阶段时,会自动执行该阶段之前的所有阶段
示例1:mvn compile
执行阶段:validate → initialize → generate-sources → process-resources → compile
示例2:mvn test
执行阶段:validate → compile → test-compile → test
(跳过了 package、install、deploy 等后续阶段)
示例3:mvn package
执行阶段:validate → compile → test → package
(自动编译、测试后才打包)
示例4:mvn install
执行阶段:validate → compile → test → package → verify → install
理解这个规则的意义:
- 你不需要手动执行每个阶段
- Maven 保证构建流程完整
- 跳过任何阶段可能导致后续阶段失败
常用构建命令
| 命令 | 完整执行流程 | 产出 |
|---|---|---|
mvn compile | validate → compile | target/classes/*.class |
mvn test | compile → test | 测试报告 |
mvn package | compile → test → package | target/*.jar |
mvn install | package → install | 本地仓库构件 |
mvn deploy | install → deploy | 远程仓库构件 |
跳过测试
有时候需要快速构建,跳过测试:
# 方式1:跳过测试执行,但编译测试代码
mvn package -DskipTests
# 方式2:跳过测试编译和执行(更快)
mvn package -Dmaven.test.skip=true
两种方式的区别:
| 方式 | 编译测试代码 | 执行测试 | 速度 |
|---|---|---|---|
| -DskipTests | ✓ 编译 | ✗ 不执行 | 较慢 |
| -Dmaven.test.skip=true | ✗ 不编译 | ✗ 不执行 | 快 |
使用场景:
| 场景 | 推荐方式 |
|---|---|
| 开发调试,快速验证 | -Dmaven.test.skip=true |
| 发布前验证 | 不要跳过 |
| CI/CD 构建 | 不要跳过 |
Site 生命周期
阶段顺序
| 阶段 | 说明 |
|---|---|
| pre-site | 生成站点前准备 |
| site | 生成项目站点文档 |
| post-site | 生成站点后处理 |
| site-deploy | 发布站点到服务器 |
执行命令
mvn site
生成的站点内容
target/site/
├── index.html ← 项目主页
├── project-info.html ← 项目信息
├── dependencies.html ← 依赖列表
├── team-list.html ← 团队成员
└── surefire-report.html ← 测试报告
实际用途:为项目生成在线文档站点,展示项目信息、依赖、团队、测试报告等。
现在实际使用情况
由于 GitHub、GitLab 等平台提供了更好的文档展示方式,Maven site 生命周期现在较少使用。
组合执行
生命周期组合
三个生命周期独立,可以组合执行:
# Clean + Default
mvn clean package # 清理后打包
mvn clean install # 清理后安装
mvn clean deploy # 清理后发布
# Clean + Default + Site
mvn clean deploy site # 清理 + 发布 + 生成文档
组合执行流程
mvn clean package
执行顺序:
1. Clean 生命周期:pre-clean → clean → post-clean
2. Default 生命周期:validate → compile → test → package
(两个生命周期顺序执行,互不干扰)
实际开发场景
场景1:日常开发调试
# 编写代码后,快速验证能否编译
mvn compile # 仅编译,不测试
# 添加了新测试,验证测试是否通过
mvn test # 编译 + 测试
# 快速打包验证
mvn package -DskipTests # 编译 + 打包,跳过测试
场景2:发布前的完整构建
# 清理 + 完整构建 + 安装到本地
mvn clean install
# 确保所有代码重新编译
# 确保所有测试通过
# 安装到本地仓库供其他模块引用
场景3:多模块项目
# 父目录下构建所有模块
mvn clean install
# 只构建某个模块及其依赖
mvn clean install -pl module-a -am
# 只构建某个模块及其下游
mvn clean install -pl module-a -amd
场景4:CI/CD 构建
# CI/CD 中推荐完整构建
mvn clean deploy
# 理由:
# 1. clean 确保干净构建
# 2. deploy 发布到仓库供团队使用
# 3. 不跳过测试,确保质量
场景5:快速修复问题
# 问题:编译报错,但不确定是什么问题
# 诊断方法:
mvn compile -X # 详细日志,查看编译过程
mvn compile -e # 显示错误堆栈
# 如果怀疑是增量编译问题:
mvn clean compile # 强制重新编译
验证生命周期执行
查看某个阶段的绑定
mvn help:describe -Dcmd=package
输出:
package' is a phase corresponding to this plugin:
org.apache.maven.plugins:maven-jar-plugin:jar
查看完整构建流程
mvn clean install -X # 详细日志,可以看到每个阶段的执行
生命周期常见问题
问题1:执行 package 但测试失败
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:test
Tests run: 5, Failures: 2
原因:package 阶段会自动执行 test,测试失败导致构建终止。
解决:
- 修复测试代码
- 或临时跳过测试
-DskipTests
问题2:编译成功但找不到 class
java.lang.ClassNotFoundException: com.example.MyClass
原因:可能是增量编译导致 target/classes 不完整。
解决:
mvn clean compile # 强制重新编译
问题3:install 后其他项目仍找不到依赖
[ERROR] Could not resolve dependencies
原因:本地仓库可能有旧的或损坏的构件。
解决:
mvn clean install -U # -U 强制更新 SNAPSHOT
rm -rf ~/.m2/repository/com/example/my-app # 删除旧构件重新安装
要点总结
- 三个独立生命周期:clean(清理)、default(构建)、site(文档)
- 执行阶段触发前置阶段:mvn package 自动执行 compile、test
- clean 确保完整构建:发布构建建议 mvn clean package
- 核心阶段:compile、test、package、install、deploy
- 跳过测试:-DskipTests(编译测试)、-Dmaven.test.skip=true(不编译)
- 组合命令:mvn clean package 最常用
- CI/CD 推荐:mvn clean deploy 不跳过测试
📝 发现内容有误?点击此处直接编辑