41-Maven 生命周期

声明周期(Lifecycle)

Maven 中有一个专业术语:声明周期(Lifecycle),它在官方文档中的名称是:**Build Lifecycle(构建生命周期)**。

我们在日常工作中,经常遇到的项目生命周期包括 编译、测试、打包、部署等,不同项目的生命周期或多或少会一些差异。

Maven 对构建的过程进行的抽象和统一,提出了 Maven生命周期 这一个抽象的概念,它的作用是定义一条执行流程,而不会完成实际的工作,在每个流程节点中的工作都会交给具体实例对象去完成。这个执行的流程中包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署、站点生成等步骤,几乎覆盖了项目构建中的所有流程节点,我们可以按需选择其中的一部分步骤生成自己的项目包。

Maven 内置了三套相互独立的生命周期(依据不同的目的,定义了三种处理项目的过程):

  • default(or build) lifecycle 负责项目的构建、发布,很常用。
  • clean lifecycle 负责清理项目,在进行真正的构建之前进行一些清理工作,比较常用。
  • site lifecycle 负责生成项目站点,即API文档信息网站,不常用。

生命周期是由阶段组成的

Each of these build lifecycles is defined by a different list of build phases, wherein a build phase represents a stage in the lifecycle.

每个声明周期由若干不同的阶段(Phase)组成。阶段代表了生命周期的特殊步骤。

例如,default lifecycle 由下列阶段组成(这里列出了部分阶段,完整阶段下文会介绍)。

  • validate 验证项目是正确的,所有必要的信息都是可用的。
  • compile 编译项目源代码。
  • test 使用单元测试框架测试编译后的源代码。
  • package 获取已编译的代码,并将其打包为可发行的格式,例如JAR。
  • verify运行任意的检查来验证项目包有效且达到质量标准。
  • install将包安装到本地仓库,供本地项目使用。
  • deploy将包发布到远程仓库(remote repository),方便其他开发人员和项目共享。

注意:

  • 生命周期阶段是按(在生命周期中定义的)顺序执行的。例如,在执行package阶段时,会先按顺序执行validate、compile、test阶段,最后执行package阶段。

  • 没有绑定插件目标的阶段,在生命周期中是不会被调用的。

阶段是由插件目标组成的

However, even though a build phase is responsible for a specific step in the build lifecycle, the manner in which it carries out those responsibilities may vary. And this is done by declaring the plugin goals bound to those build phases.

阶段对生命周期的特殊步骤负责,它履行职责的方式可能不同,取决于绑定到阶段的插件目标。简而言之,阶段的执行依赖于插件目标。

例如:compile阶段履行编译职责,依赖于插件目标 compiler:compile,这里compiler代表了插件maven-compiler-plugin(本质是maven-compiler-plugin-3.1.jar),compile表示(插件)目标(本质上应该是要选择类中的一个方法执行,具体还有看源码,主要就是选择一个模块执行)。

A plugin goal represents a specific task (finer than a build phase) which contributes to the building and managing of a project. It may be bound to zero or more build phases. A goal not bound to any build phase could be executed outside of the build lifecycle by direct invocation.

Moreover, if a goal is bound to one or more build phases, that goal will be called in all those phases.

Furthermore, a build phase can also have zero or more goals bound to it. If a build phase has no goals bound to it, that build phase will not execute. But if it has one or more goals bound to it, it will execute all those goals.

内容较多,挑选主要内容翻译。

  1. 插件目标代表明确的任务。

    例如:jar:jar把编译的二进制class文件打包,格式JAR;install:install把打包文件安装到本地仓库等。

  2. 一个生命周期阶段可以绑定零或多个插件目标。

  3. 某生命周期阶段没有绑定插件目标(或者说绑定零个插件目标),它将不会执行。绑定多个按绑定的先后顺序执行。例如

    • 打包方式为pom时,生命周期阶段package没有绑定任何插件目标,因此不会执行。打包方式为pom时主要用于父项目,统一管理依赖。不进行打包,也是可以理解的。

    • 打包方式为maven-plugin时,生命周期阶段package绑定了多个(实际为2个)插件目标, jar:jarplugin:addPluginArtifactMetadata。插件按绑定顺序执行。

  4. 一个插件目标可以绑定到零个或者多个生命周期阶段上。如果某插件目标没有绑定到生命周期阶段上(即绑定到零个生命周期阶段),它执行任务的方式是 直接调用

    例如:

    • 插件目标install:install,它被绑定到了install阶段,在命令行中输入mvn install,首先执行default lifecycle 中install之前的所有生命周期阶段,最后执行install阶段,此时,插件目标install:install执行任务。假设,还有其他插件目标绑定到install阶段,也会被调用来执行相应的任务。

    • 有些插件目标,如 tomcat7:run 没有绑定到任务生命周期阶段,它想要执行任务,可以通过直接调用 direct invocation,在命令行中输入mvn tomcat7:run,就可以执行任务。

    • 另外,在命令行输入install:install,只会执行安装包到本地仓库的任务。如果,install阶段之前的所有生命周期阶段没有执行,此时会报错,因为没有install之前的阶段履行职责,可能根本不存在jar包。

    简言之,插件目标执行任务,可以直接调用。也可以由阶段调用。

生命周期及履行职责

下面列出了default、clean和site生命周期的所有阶段,它们按照在下表中定义的顺序执行的。当执行某个阶段,先执行其之前的所有阶段,然后执行该阶段。用连字符命名的阶段(pre-*post-_process-_ )通常不会直接从命令行调用。它们履行的职责主要是生成一些中间产物等等

Clean Lifecycle (clean 经常用)

Phase Description
pre-clean 执行清理前需要完成的工作
clean (经常用) 清理上一次构建生成的文件
post-clean 执行清理后需要完成的工作

Default Lifecycle (很很很常用)

Phase Description
validate(校验) 校验项目是否正确并且所有必要的信息可以完成项目的构建过程。
initialize(初始化) 初始化构建状态,比如设置属性值。
generate-sources(生成源代码) 生成包含在编译阶段中的任何源代码。
process-sources(处理源代码) 处理源代码,比如说,过滤任意值。
generate-resources(生成资源文件) 生成将会包含在项目包中的资源文件。
process-resources (处理资源文件) 复制和处理资源到目标目录,为打包阶段最好准备。
compile(编译) 编译项目的源代码。
process-classes(处理类文件) 处理编译生成的文件,比如说对Java class文件做字节码改善优化。
generate-test-sources(生成测试源代码) 生成包含在编译阶段中的任何测试源代码。
process-test-sources(处理测试源代码) 处理测试源代码,比如说,过滤任意值。
generate-test-resources(生成测试资源文件) 为测试创建资源文件。
process-test-resources(处理测试资源文件) 复制和处理测试资源到目标目录。
test-compile(编译测试源码) 编译测试源代码到测试目标目录.
process-test-classes(处理测试类文件) 处理测试源码编译生成的文件。
test(测试) 使用合适的单元测试框架运行测试(Juint是其中之一)。
prepare-package(准备打包) 在实际打包之前,执行任何的必要的操作为打包做准备。
package(打包) 将编译后的代码打包成可分发格式的文件,比如JAR、WAR或者EAR文件。
pre-integration-test(集成测试前) 在执行集成测试前进行必要的动作。比如说,搭建需要的环境。
integration-test(集成测试) 处理和部署项目到可以运行集成测试环境中。
post-integration-test(集成测试后) 在执行集成测试完成后进行必要的动作。比如说,清理集成测试环境。
verify (验证) 运行任意的检查来验证项目包有效且达到质量标准。
install(安装) 安装项目包到本地仓库,这样项目包可以用作其他本地项目的依赖。
deploy(部署) 将最终的项目包复制到远程仓库中与其他开发者和项目共享。

Site Lifecycle (不常用)

Phase Description
pre-site 执行一些需要在生成站点文档之前完成的工作
site 生成项目的站点文档
post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
site-deploy 将生成的站点文档部署到特定的服务器上

绑定插件目标

绑定插件目标主要有两种方式:

  • 第一种方式,内置绑定。使用Maven内置的绑定。Maven根据不同的打包方式,为某些阶段默认绑定插件目标。由于其打包生成的目标包不同,因此阶段和阶段绑定的插件目标也存在差异。

  • 第二种方式,自定义绑定。通过配置pom.xml文件,为阶段绑定插件目标。如此,阶段可能包含多个插件目标,其执行顺序为,先执行maven内置的为阶段绑定的目标(如果该阶段绑定了插件目标的话),然后按照你在pom文件中配置的插件目标的顺序依次执行(如果你为该阶段配置了多个插件目标的话)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <plugin>  
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.6</version>
    <executions>
    <execution>
    <id>attach-resources</id>
    <!-- 生命周期的阶段 verify -->
    <phase>verify</phase>
    <goals>
    <!-- 插件目标 -->
    <goal>jar-no-fork</goal>
    </goals>
    </execution>
    </executions>
    </plugin>

插件调用方式

插件有如下几种调用方式:

  1. **mvn 生命周期阶段**:如mvn pre-clean,maven 会自动执行与该生命周期绑定的插件目标。

  2. **mvn groupId:artifactId[:version]:goal**,如 mvn org.apache.maven.plugins:maven-clean-plugin:3.1.0:clean,对于版本号 version 来说是可以省略的,如果省略 maven 会使用本地仓库中最新的版本。

  3. **mvn 插件前缀:goal**:插件前缀可以理解为插件的标识,用于简化插件的调用,例如 mvn spring-boot:run 中的 spring-boot 就是 spring-boot-maven-plugin 插件的前缀,自定义插件如果遵循 xxx-maven-plugin 的形式,maven 默认会将 maven-plugin 前面的内容作为插件前缀。

举例

我们以执行 mvn clean 为例说明

首先,我们要知道,clean生命周期有三个phase:pre-clean、clean、post-clean。我们现在要使用的是clean阶段。而每一个phase包含0个或多个插件,我们用如下方式查看对应的插件。

首先,我们在spring-boot-dependencies.pom中查找对应的插件

1
2
3
4
5
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>${maven-clean-plugin.version}</version>
</plugin>

使用如下命令查看这个插件的详细信息

1
2
3
4
5
6
7
8
# 语法,插件标识可以是 groupId:artifactId[:version]
mvn help:describe -Dplugin=插件标识

# 示例
mvn help:describe -Dplugin=org.apache.maven.plugins:maven-clean-plugin -Ddetail

# 还可以直接使用插件名替换 坐标进行简化
mvn help:describe -Dplugin=compiler

  • 第一种调用方式:mvn 生命周期阶段

    1
    mvn clean
  • 第二种调用方式:

    1
    mvn org.apache.maven.plugins:maven-clean-plugin:3.1.0:clean
  • 第三种调用方式:

    1
    mvn clean:clean

41-Maven 生命周期
https://flepeng.github.io/021-Java-13-Maven-41-Maven-生命周期/
作者
Lepeng
发布于
2021年4月22日
许可协议