Skip to content

Maven 生命周期介绍

1. 核心概念

1.1 什么是 Maven 生命周期

Maven 的核心思想是把一次构建过程抽象成一条标准化流水线。官方称它为 build lifecycle,也就是从校验、编译、测试、打包到发布的一组固定阶段。

这样做的价值在于:开发者不需要为每个项目重新发明构建脚本,只需要记住少量命令,再由 pom.xml 告诉 Maven 当前项目在每个阶段该执行什么任务。

1.2 生命周期、阶段、目标三者的区别

概念 粒度 作用 典型例子
lifecycle 最大 定义一整条构建流程 defaultcleansite
phase 中等 生命周期中的一个阶段 compiletestpackage
goal 最小 插件真正执行的具体任务 compiler:compilejar:jar

可以把它理解成:

  • lifecycle 是生产线。
  • phase 是生产线上的工位。
  • goal 是工位里真正干活的动作。

很多人把 package 当成“命令”,但从 Maven 语义上说,它首先是一个 phase。真正执行打包动作的,通常是某个插件绑定到这个阶段上的 goal,例如 jar:jarwar:war

2. Maven 内置的三套生命周期

2.1 default 生命周期

default 是最重要的一套生命周期,负责项目从源码到最终制品的构建与发布。平时执行的 compiletestpackageinstalldeploy,本质上都属于这条生命周期。

绝大多数面试问题中的“Maven 生命周期”,默认都是在问 default 生命周期。

2.2 clean 生命周期

clean 生命周期的职责很单一:清理上一次构建产生的输出物,例如 target 目录。它只有三步:

  1. pre-clean
  2. clean
  3. post-clean

因此,mvn clean package 不是在一条生命周期里执行两个阶段,而是先执行 clean 生命周期,再执行 default 生命周期直到 package 阶段

2.3 site 生命周期

site 生命周期用于生成项目站点文档,例如测试报告、插件报告、项目描述页等。它在现代业务项目里使用频率不如 defaultclean 高,但仍是 Maven 官方内置生命周期之一。

它的常见阶段包括:

  1. pre-site
  2. site
  3. post-site
  4. site-deploy

3. default 生命周期的执行链路

3.1 关键阶段概览

下面这些阶段是面试中最常被问到的主干阶段:

阶段 作用 面试要点
validate 校验项目是否完整、配置是否有效 还不做编译
compile 编译主源码 产物进入 target/classes
test 执行单元测试 通常不依赖最终包
package 打成可分发制品 常见是 jarwar
verify 做集成测试结果校验或质量校验 package 更完整
install 安装到本地仓库 供本机其他项目依赖
deploy 发布到远程仓库 供团队或环境共享

3.2 完整阶段顺序

default 生命周期的完整顺序如下:

  1. validate
  2. initialize
  3. generate-sources
  4. process-sources
  5. generate-resources
  6. process-resources
  7. compile
  8. process-classes
  9. generate-test-sources
  10. process-test-sources
  11. generate-test-resources
  12. process-test-resources
  13. test-compile
  14. process-test-classes
  15. test
  16. prepare-package
  17. package
  18. pre-integration-test
  19. integration-test
  20. post-integration-test
  21. verify
  22. install
  23. deploy

面试里最容易答错的一点是:执行某个阶段时,Maven 会把当前生命周期中它之前的所有阶段一起执行掉

例如下面这条命令:

mvn package

它不是只做“打包”这一件事,而是会顺序执行到 package 为止,也就是先校验、编译、处理资源、跑单测,最后才打包。

3.3 为什么很多场景推荐 mvn verify

Maven 官方文档明确提到,如果你不确定应该调用哪个阶段,通常更推荐调用 mvn verify

原因是 verifypackage 更靠后,它会在完成打包之后,再继续执行集成测试校验、覆盖率校验、代码规范校验等附加质量检查。对于持续集成环境,它往往比 package 更符合“构建完成”的语义。

4. phasepackaginggoal 如何协作

4.1 为什么同样是 package,不同项目打包结果不同

因为 phase 只是阶段名称,真正执行的任务取决于:

  1. 项目的 packaging
  2. packaging 对默认 goal 的绑定
  3. 你在 pom.xml 里额外配置的插件执行

例如,官方文档给出的默认绑定里:

packaging package 阶段的典型 goal 结果
jar jar:jar 生成 jar
war war:war 生成 war
maven-plugin jar:jarplugin:addPluginArtifactMetadata 生成 Maven 插件制品
pom 无实际打包动作 通常只做聚合或父 POM

这也是为什么聚合工程通常声明:

<packaging>pom</packaging>

此时它本身一般不产出业务可执行包,而是负责统一模块、依赖版本或插件配置。

4.2 jar 工程的默认绑定是什么

以最常见的 jar 工程为例,官方文档给出的默认绑定大致如下:

阶段 默认执行的 goal
process-resources resources:resources
compile compiler:compile
process-test-resources resources:testResources
test-compile compiler:testCompile
test surefire:test
package jar:jar
install install:install
deploy deploy:deploy

所以从源码角度看,phase 本身不直接“干活”,goal 才是实际执行单元。Maven 生命周期本质上是在驱动一组插件目标按顺序运行。

4.3 如何把自定义任务挂到生命周期里

如果你希望某个插件在固定阶段自动执行,就需要在 pom.xml 中通过 <executions>goal 绑定到某个 phase

<build>
  <plugins>
    <plugin>
      <groupId>com.example</groupId>
      <artifactId>demo-plugin</artifactId>
      <executions>
        <execution>
          <id>run-on-verify</id>
          <phase>verify</phase>
          <goals>
            <goal>check</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

上面的配置表示:当构建执行到 verify 阶段时,额外执行一次 demo-plugin:check

要注意两点:

  • 只声明插件,不一定会执行你想要的 goal。很多场景必须显式写 <executions>
  • 如果同一个阶段绑定了多个 goal,官方文档说明它们会按声明顺序执行;而 packaging 自带的默认绑定会先执行,再执行你在 POM 中新增的绑定。

5. 常见命令的差异与使用场景

5.1 testpackageverifyinstalldeploy 的区别

命令 会执行到哪里 适用场景
mvn test 执行到 test 只想编译并跑单元测试
mvn package 执行到 package 本地快速产出 jarwar
mvn verify 执行到 verify 希望连质量校验、集成测试链路一起跑完
mvn install 执行到 install 需要把产物安装到本地仓库给别的本地项目使用
mvn deploy 执行到 deploy 需要把产物发布到远程仓库

三者最常被混淆的是 packageinstalldeploy

  • package:只把当前项目打成包,产物通常还只在当前工程的 target 目录里。
  • install:在 package 基础上,把产物放进本地仓库,路径通常位于 ~/.m2/repository
  • deploy:在 install 之后,再把产物推送到远程仓库,例如公司私服或制品仓库。

5.2 clean package 到底做了什么

mvn clean package

这条命令可以拆成两段理解:

  1. 执行 clean 生命周期,把上一次构建残留删掉。
  2. 执行 default 生命周期直到 package

因此,它非常适合作为本地“干净构建”的通用命令。

5.3 为什么不建议直接调用 integration-test

官方文档特别强调,像 pre-*post-*process-* 这类中间阶段通常不应该直接从命令行调用。

integration-test 为例,很多插件会在 pre-integration-test 阶段拉起容器环境,在 post-integration-test 阶段清理环境,在 verify 阶段汇总报告。你如果只手工执行:

mvn integration-test

就可能出现测试容器没被正确清理、报告没生成完整、进程悬挂等问题。更稳妥的方式通常是执行:

mvn verify

6. 多模块项目中的生命周期

6.1 根工程为什么常用 pom 打包

多模块项目的根工程通常承担两类职责:

  1. 作为父 POM,统一依赖版本、插件版本、公共属性。
  2. 作为聚合工程,统一组织多个子模块一起构建。

这类工程通常配置为:

<packaging>pom</packaging>

因为它的重点不是产出一个业务包,而是管理整个模块集合。

6.2 在根目录执行命令会发生什么

官方文档说明,在多模块场景下执行:

mvn clean deploy

Maven 会遍历每个子项目,先执行 clean,再执行 deploy 以及其之前的所有前置阶段。也就是说,根目录的一条命令,实际会驱动整棵模块树按生命周期逐步构建。