04-Maven-第 4 章 项目构建:生命周期与插件

Maven-第 4 章 项目构建:生命周期与插件

摘要: 在上一章,我们掌握了如何管理项目的“原材料”——依赖。本章,我们将学习如何将这些原材料加工成最终产品。我们将深入 Maven 的第二个核心能力:项目构建。您将学习到什么是 生命周期,它如何为所有 Java 项目提供一套标准化的构建流程,并最终理解到,所有实际工作都是由其背边的“工匠”——插件——来完成的。

4.1. 构建生命周期:Maven 的标准化流程

[生命周期(Lifecycle)是 Maven 中最具创新性的概念之一。它不是一个具体的程序,而是一套抽象的、标准化的项目构建流程规范。理解了生命周期,就理解了 Maven 自动化构建的精髓。]


4.1.1. 什么是生命周期?

我们可以将 Maven 的生命周期想象成一条“软件生产流水线”。这条流水线被预先定义好了,包含了一系列固定的、有序的“工位”,这些工位在 Maven 中被称为 阶段 (Phase)

例如,一条典型的生产线可能包含“编译”、“测试”、“打包”等工位。无论我们要生产什么产品(项目),都必须依次经过这些工位。这种标准化的流程,确保了所有产出(无论是您自己还是团队其他成员构建的项目)都遵循同样的规范,具有同样的高品质。


4.1.2. Maven 的三大生命周期

Maven 内置了三条完全独立的生命周期(流水线),它们各自负责不同的任务,互不干扰。

🧹 clean 生命周期:清理工作区

这条流水线的任务非常专一:打扫战场
它的主要目标是删除上一次构建时生成的所有文件,最典型的就是删除整个 target 目录,确保我们能在一个干净的环境下进行全新的构建。

它包含以下核心阶段:

  • pre-clean: 执行清理前需要完成的工作。
  • clean: (核心) 删除上一次构建生成的所有文件。
  • post-clean: 执行清理后需要完成的工作。

⚙️ default 生命周期:核心生产线

这是 最重要、最核心 的一条流水线,定义了项目从源代码到最终产物的完整构建过程。
我们日常绝大部分的 Maven 操作都与它相关。

它的核心阶段非常多,常见的如:

  • validate
  • compile
  • test
  • package
  • verify
  • install
  • deploy

我们将在下一节中对这些阶段进行详细介绍。

📄 site 生命周期:报告生成线

这条流水线的任务是为项目生成一个文档站点,包含项目的详细信息、各类测试报告、代码质量分析等。

它的核心阶段包括:

  • pre-site: 执行站点生成前需要完成的工作。
  • site: (核心) 生成项目站点文档。
  • post-site: 执行站点生成后需要完成的工作。
  • site-deploy: 将生成的站点部署到指定的服务器。

4.1.3. 生命周期核心原则

1. 独立性

三大生命周期是 完全相互相互独立的。调用其中一条生命周期中的任何阶段,都不会对另外两条生命周期产生任何影响。

例如,我们执行 mvn clean 命令,它只会调用 clean 生命周期的 clean 阶段,而不会触及 default 生命周期的任何操作。

这也是为什么我们经常使用 mvn clean install 这样的组合命令。这实际上是 Maven 先后执行了两个独立的指令:首先调用 clean 生命周期的 clean 阶段进行清理,然后调用 default 生命周期的 install 阶段进行构建和安装。

2. 顺序性

同一个生命周期内部,所有阶段都是严格有序的。当我们调用一个阶段时,Maven 会自动从该生命周期的起始阶段开始,按顺序执行,直到我们指定的阶段为止。

例如,default 生命周期的顺序是 ... -> compile -> test -> package -> ...。当我们执行 mvn package 命令时,Maven 实际上会依次执行 validate, compile, test, package 等所有在 package 之前(包括 package 自身)的阶段。这个特性极大地简化了我们的操作,我们无需手动按顺序敲入一长串命令。


4.2. 详解 default 生命周期的核心阶段

[现在,我们聚焦于最核心的 default 生命周期,通过一个时间线的形式,来详细观察一个项目是如何从源代码一步步“进化”成最终产物的。]

项目起始

compile

阶段: compile

这是构建过程的第一个重要里程碑。在此阶段,Maven 会调用编译器(如 javac),将我们编写的位于 src/main/java 目录下的所有 .java 源代码文件,编译成 JVM 可以执行的 .class 字节码文件,并输出到 target/classes 目录下。

test

阶段: test

为了保证项目质量,test 阶段会执行所有的单元测试。它首先会编译 src/test/java 目录下的测试代码(test-compile 阶段),然后运行这些测试。如果任何一个单元测试失败,整个构建过程将在此处 立即中止,这是保证项目健康度的重要关卡。

package

阶段: package

当所有代码编译完成并通过测试后,package 阶段会将 target/classes 目录下的 .class 文件、以及 src/main/resources 目录下的配置文件等资源,按照项目的打包类型(由 pom.xml 中的 <packaging> 标签定义),打包成一个单独的可分发文件。

  • 如果 <packaging>jar,则会生成一个 .jar 文件。
  • 如果 <packaging>war,则会生成一个 .war 文件。

.jar 主要用于封装可独立运行的 Java 应用程序或库,包含类文件、资源文件等;.war 是 Web 应用程序归档文件,除了包含应用代码和资源,还包含 Web 相关配置,用于部署到 Web 服务器如 Tomcat 等。

这个最终的产物会被放置在 target 目录下。

install

阶段: install

install 阶段不仅仅是打包。它会执行 package 的所有操作,然后额外多做一个非常重要的工作:将 package 阶段生成的项目产物(如 .jar 文件)复制并安装到我们的 “本地仓库” 中。

这么做的好处是,一旦一个项目被 install,我们本机上的其他 Maven 项目就可以在自己的 pom.xml 中像依赖第三方库一样,直接依赖这个项目了。

deploy

阶段: deploy

这是 default 生命周期的最后一个核心阶段。deploy 会执行 install 的所有操作,然后更进一步:将项目产物 上传并部署到“远程仓库”(通常是公司的私服 Nexus)。

一旦项目被 deploy,整个团队的所有成员就都可以通过配置他们的 Maven 来依赖和使用这个项目了,这是团队协作和成果共享的关键步骤。

这个是我们后续的详细讲解的配置相关内容!


4.3. 插件:Maven 的真正执行者

[生命周期和阶段都只是“规范”和“流程图”,它们本身并不能做任何实际的工作。那么,编译、打包这些具体的操作到底是谁完成的呢?答案就是——插件 (Plugin)。]


4.3.1. 插件与生命周期的关系

我们可以这样理解三者的关系:

  • 生命周期 (Lifecycle): 定义了项目的 顶级构建流程(如 default)。
  • 阶段 (Phase): 构成了生命周期的 有序步骤(如 compile, package)。
  • 插件目标 (Plugin Goal): 真正执行任务的“工人”

Maven 的运行机制,就是将特定的“插件目标”绑定到特定的“生命周期阶段”上。当 Maven 执行到一个阶段时,就会调用所有绑定在该阶段上的插件目标来完成具体工作。


4.3.2. 核心插件与目标(Goal)介绍

下表展示了 default 生命周期中一些核心阶段与其默认绑定的插件和目标:

PhasePluginGoal功能描述
compilemaven-compiler-plugincompile编译 src/main/java 下的源码。
testmaven-surefire-plugintest运行 src/test/java 下的单元测试。
packagemaven-jar-pluginjar将项目打包成 JAR 文件。
installmaven-install-plugininstall将项目安装到本地仓库。
deploymaven-deploy-plugindeploy将项目部署到远程仓库。

4.3.3. 自定义插件配置

虽然 Maven 为各阶段都绑定了功能完善的默认插件,但我们也可以在 pom.xml<build> 标签中对这些插件进行自定义配置,以满足项目的特殊需求。

最常见的场景就是为项目单独指定编译时使用的 JDK 版本,这可以覆盖 settings.xml 中的全局配置,保证项目在任何环境下都使用我们期望的 JDK 版本进行编译,极大地增强了项目的可移植性。

1
2
3
4
5
6
7
8
9
10
11
12
13
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>

<source> 标签指定了要使用的 Java 源码版本,<target> 标签指定编译生成的字节码目标版本,按配置编译出的代码就对应相应版本特性,

现在执行 mvn compile 命令时,就可以打包指定的 Java 版本了


4.4. 高频面试题

Q: 请说一下 mvn clean, compile, package, install 这几个命令有什么区别和联系?

A: 这是一个非常经典的 Maven 面试题,我们可以从以下四个方面来回答:

1. 功能区别

  • mvn compile: 只执行 default 生命周期到 compile 阶段。它的作用是将主程序代码(src/main/java)编译成 .class 文件,输出到 target/classes 目录。
  • mvn package: 执行 default 生命周期到 package 阶段。它会先完成 compile 和 test 的所有工作,然后将项目打包成一个 .jar.war 文件,存放在 target 目录下。
  • mvn install: 执行 default 生命周期到 install 阶段。它会先完成 package 的所有工作,然后把最终的包文件安装到我们的 本地仓库 中。
  • mvn clean: 执行 clean 生命周期的 clean 阶段。它的功能非常纯粹,就是删除整个 target 目录,清理之前构建的所有产物。

2. 从属关系

  • compile, package, install 三者都属于 default 生命周期。
  • clean 属于 clean 生命周期。

3. 递进关系

  • 在 default 生命周期中,三者是严格的递进关系:install 包含了 package 的所有功能,package 包含了 compile 的所有功能。
  • clean 与 default 生命周期的任何阶段都是 完全独立 的。

4. 使用场景

  • mvn compile: 只想检查代码是否有编译错误时使用。
  • mvn package: 当我们需要得到项目的可执行/可部署包(如 .jar 文件)时使用。这是最常用的打包命令。
  • mvn install: 当我们本地的另一个项目需要依赖此项目时使用。通过 install,我们将此项目变成了可被其他项目依赖的“本地库”。
  • mvn clean installmvn clean package: 这是最推荐的组合命令。通过先 clean,可以确保我们是在一个完全干净的环境下进行全新的打包或安装,避免了旧的编译文件可能带来的干扰。