default 生命周期
本章承接"生命周期概述",深入讲解 default 生命周期——Maven 最核心、最常用的构建流水线。理解 validate 到 deploy 各阶段的输入输出和职责边界,是掌握 Maven 构建原理、精准排查构建失败、设计 CI/CD 流水线的关键。
核心机制
default 生命周期是项目的主构建生命周期,用于构建和分发项目。其核心阶段包括 validate → compile → test → package → verify → install → deploy。虽然生命周期中实际包含二十多个阶段,但日常开发中只需掌握上述核心阶段的含义和顺序。
default 生命周期的核心阶段
default 生命周期是 Maven 的"主流水线",负责从源代码到可部署产物的完整转化。以下是核心阶段的详细说明:
| 阶段 | 职责 | 典型输入 | 典型输出 | 默认绑定的插件目标 |
|---|---|---|---|---|
| validate | 验证项目结构和 POM 的合法性 | pom.xml | 验证报告 | 无默认绑定(可自定义) |
| compile | 编译主源代码 | src/main/java/*.java | target/classes/*.class | maven-compiler-plugin:compile |
| test | 运行单元测试 | src/test/java/*Test.java + target/classes/ | 测试报告 + target/surefire-reports/ | maven-surefire-plugin:test |
| package | 将编译结果打包为可分发的格式 | target/classes/ | target/*.jar 或 *.war | maven-jar-plugin:jar(JAR 项目) |
| verify | 对打包结果进行完整性检查 | target/*.jar | 验证报告 | 无默认绑定(可自定义) |
| install | 将包安装到本地仓库 | target/*.jar | ~/.m2/repository/.../*.jar | maven-install-plugin:install |
| deploy | 将包发布到远程仓库/私服 | target/*.jar | 远程仓库中的构件 | maven-deploy-plugin:deploy |
阶段的输入输出链
default 生命周期的阶段之间形成了清晰的数据流:
src/main/java/*.java
↓ [compile]
target/classes/*.class
↓ [test]
测试通过报告
↓ [package]
target/employee-system-1.0.0.jar
↓ [verify]
验证通过报告
↓ [install]
~/.m2/repository/com/feixiang/employee-system/1.0.0/employee-system-1.0.0.jar
↓ [deploy]
http://nexus.feixiang.tech/repository/company-releases/.../employee-system-1.0.0.jar
这个链条体现了 Maven 构建的阶段性递进:每个阶段的输出是下一个阶段的输入,构建产物从源代码逐步转化为可部署的远程构件。
阶段的累积性再强调
由于累积性,执行后面的阶段会自动触发前面的阶段:
| 执行的命令 | 实际执行的阶段链 |
|---|---|
mvn compile | validate → compile |
mvn test | validate → compile → test |
mvn package | validate → compile → test → package |
mvn install | validate → compile → test → package → verify → install |
mvn deploy | validate → compile → test → package → verify → install → deploy |
生活类比:食品加工厂
想象一家将新鲜水果加工成罐头的食品厂:
- validate = 原料验收:检查送来的水果是否新鲜、农药残留是否达标、包装标签是否完整。如果原料不合格,整批退货,后续工序不启动
- compile = 清洗切割:把水果洗净、去皮、切块,变成"半成品"(
.class文件)。这是核心加工的第一步 - test = 质检抽检:从切割好的半成品中抽样,检测糖分、酸度、微生物指标。如果抽检不合格,整批半成品报废
- package = 灌装封口:把合格的半成品装入罐头瓶、抽真空、封盖,变成"成品"(JAR 包)
- verify = 出厂检验:对成品罐头进行跌落测试、密封性测试、保质期模拟。确保送到消费者手里不会漏、不会坏
- install = 入库分销中心:把成品罐头运到全国各大超市的仓库(本地仓库),供各地门店(其他项目)上架销售
- deploy = 出口海外:把罐头装上远洋货轮,运到国外经销商的仓库(远程仓库/私服),进入国际市场
这个类比的关键在于:每个阶段都有明确的输入、输出和验收标准,前一阶段的输出不合格,后一阶段不会启动。这也是 Maven 构建失败时,你需要根据报错信息判断"哪个工位出了问题"的原因。
图示
上图展示了 default 生命周期的完整阶段链和数据流。每个阶段的输出(绿色/蓝色节点)成为下一个阶段的输入,形成一条从源代码到远程构件的完整流水线。
完整示例
场景
飞翔科技的 employee-system 项目完成了 1.0.0 版本的开发,CTO 大翔要求架构师白歌向团队演示 default 生命周期各阶段的实际效果,确保每个人都理解 mvn compile、mvn test、mvn package、mvn install、mvn deploy 的区别和适用场景。
操作前:项目已准备好发布
项目结构:
employee-system/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/com/feixiang/employee/
│ │ │ ├── EmployeeService.java
│ │ │ └── EmployeeController.java
│ │ └── resources/application.properties
│ └── test/
│ └── java/com/feixiang/employee/
│ └── EmployeeServiceTest.java
pom.xml 关键配置:
<project>
<groupId>com.feixiang</groupId>
<artifactId>employee-system</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<distributionManagement>
<repository>
<id>company-releases</id>
<url>http://nexus.feixiang.tech/repository/company-releases/</url>
</repository>
</distributionManagement>
</project>
操作步骤
白歌依次执行各阶段命令,展示输入输出的变化。
步骤 1:compile 阶段
mvn compile
输出:
[INFO] --- maven-compiler-plugin:3.10.1:compile (default-compile) @ employee-system ---
[INFO] Compiling 2 source files to /home/baige/employee-system/target/classes
输入:src/main/java/ 下的 2 个 .java 文件
输出:target/classes/com/feixiang/employee/ 下的 2 个 .class 文件
步骤 2:test 阶段
mvn test
输出:
[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ employee-system ---
[INFO] Compiling 1 test source file to /home/baige/employee-system/target/test-classes
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ employee-system ---
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ employee-system ---
输入:src/test/java/EmployeeServiceTest.java + target/classes/(被测试的类)
输出:target/test-classes/(编译后的测试类) + target/surefire-reports/(测试报告)
注意:由于累积性,mvn test 自动先执行了 compile,所以 target/classes/ 已经存在。
步骤 3:package 阶段
mvn package
输出:
[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ employee-system ---
[INFO] Building jar: /home/baige/employee-system/target/employee-system-1.0.0.jar
输入:target/classes/ + src/main/resources/
输出:target/employee-system-1.0.0.jar
注意:由于累积性,mvn package 自动先执行了 compile 和 test。如果测试失败,package 阶段不会执行。
步骤 4:install 阶段
mvn install
输出:
[INFO] --- maven-install-plugin:3.1.0:install (default-install) @ employee-system ---
[INFO] Installing /home/baige/employee-system/target/employee-system-1.0.0.jar to /home/baige/.m2/repository/com/feixiang/employee-system/1.0.0/employee-system-1.0.0.jar
[INFO] Installing /home/baige/employee-system/pom.xml to /home/baige/.m2/repository/com/feixiang/employee-system/1.0.0/employee-system-1.0.0.pom
输入:target/employee-system-1.0.0.jar
输出:~/.m2/repository/com/feixiang/employee-system/1.0.0/ 下的 JAR 和 POM
步骤 5:deploy 阶段
mvn deploy
输出:
[INFO] --- maven-deploy-plugin:3.1.1:deploy (default-deploy) @ employee-system ---
[INFO] Uploading to company-releases: http://nexus.feixiang.tech/repository/company-releases/com/feixiang/employee-system/1.0.0/employee-system-1.0.0.jar
[INFO] Uploaded to company-releases: http://nexus.feixiang.tech/.../employee-system-1.0.0.jar (12 kB at 156 kB/s)
输入:target/employee-system-1.0.0.jar + pom.xml
输出:Nexus 私服 company-releases 仓库中的构件
操作结果
变化分析:
- 小崔理解了
compile只是"半成品",不能独立运行;package才是"成品",可以java -jar执行 - 黄俪明白了为什么联调时要先
mvn install——只有 install 到本地仓库后,她的前端项目(通过 Maven 引用了employee-system)才能解析到最新版本 - 李眉确认了 Jenkins 流水线的正确命令是
mvn clean deploy——deploy 会自动走完前面所有阶段,最终把产物发布到私服,供生产环境拉取 - 大翔在项目管理工具中标记 1.0.0 版本为"已发布",因为 deploy 成功意味着构件已进入公司级仓库
易错点与常见问题
误区一:mvn compile 会执行 test
错误认知:"我执行 mvn compile,Maven 应该会顺便跑一下测试吧?毕竟编译完测一下很正常。"
纠正:mvn compile 只执行到 compile 阶段,不会触发 test。测试阶段在 compile 之后,只有显式执行 mvn test 或更后面的阶段(如 mvn package)时,测试才会运行。这个设计是有意为之——编译是高频操作(写几行代码就编译一下),测试是低频操作(通常写完一个功能再统一测试)。如果每次编译都跑测试,开发效率会大幅下降。
误区二:install 和 deploy 是一样的
错误认知:"mvn install 和 mvn deploy 都是'发布',只是名字不同。"
纠正:两者的发布目标完全不同:
| 命令 | 目标仓库 | 范围 | 用途 |
|---|---|---|---|
mvn install | 本地仓库 ~/.m2/repository | 仅当前开发者 | 本地跨项目引用、临时测试 |
mvn deploy | 远程仓库/私服 | 全公司/全网 | 正式版本发布、CI/CD 交付 |
install 是"本地发布",只有你自己能用;deploy 是"远程发布",团队所有人都能下载。在 CI/CD 流水线中,应该用 deploy;在本地开发时,如果另一个项目需要引用当前项目的最新代码,用 install。
误区三:跳过测试是安全的
错误认知:"赶时间的时候用 mvn package -DskipTests,反正代码我本地测过了,跳过 Maven 的测试没问题。"
纠正:-DskipTests 确实跳过了 maven-surefire-plugin 的测试执行,但测试代码仍然会被编译。更危险的是 -Dmaven.test.skip=true,它连测试代码的编译都跳过。如果测试代码里有编译错误(如引用了已删除的 API),这个参数会让错误被掩盖,直到其他开发者拉取代码后才发现。跳过测试应该是临时手段,而非常态。
小结
default 生命周期是 Maven 的"主构建流水线",由 validate、compile、test、package、verify、install、deploy 等阶段组成。每个阶段有明确的输入输出,形成从源代码到远程构件的完整数据流。阶段的累积性意味着执行后面的阶段会自动触发前面的所有阶段。理解各阶段的职责边界,是选择正确 Maven 命令(compile vs package vs install vs deploy)的基础。
本章与全局的关系:本章深入讲解了"如何构建和发布项目"。下一章"site 生命周期"将讲解 Maven 的文档生成能力——如何自动生成项目报告站点。