Appearance
Maven 生命周期
1. 构建生命周期基础
有三种内置的构建生命周期:default、clean 和 site。default 生命周期处理你的项目部署,clean 生命周期处理项目清理,而 site 生命周期处理你的项目网站的创建。
1.1. 构建生命周期由阶段组成
每种构建生命周期都由不同的构建阶段定义。
例如,default 生命周期包括以下阶段:
validate:验证项目是否正确,所有必要的信息是否可用compile:编译项目的源代码test:使用适当的单元测试框架测试编译后的源代码。这些测试不应要求代码被打包或部署package:将编译后的代码打包成其可分发的格式,如 JARverify:对集成测试的结果进行任何检查,以确保满足质量标准install:将包安装到本地仓库,供其他本地项目作为依赖项使用deploy:在构建环境中完成,将最终包复制到远程仓库,与其他开发人员和项目共享
Note:要获取生命周期阶段的完整列表,请参考生命周期参考。
这些生命周期阶段(加上这里未显示的其他生命周期阶段)按顺序执行以完成 default 生命周期。鉴于上述生命周期阶段,这意味着当使用 default 生命周期时,Maven 将首先验证项目,然后尝试编译源代码,对这些源代码进行测试,打包二进制文件(例如 jar),对该包进行集成测试,验证集成测试,将验证后的包安装到本地仓库,然后将已安装的包部署到远程仓库。
1.2. 常用命令行调用
你应该选择与你的结果匹配的阶段。如果你想要你的 jar,运行 package。如果你想运行单元测试,运行 test。
如果你不确定你想要什么,首选的阶段调用是:
Bash
mvn verify此命令按顺序执行每个 default 生命周期阶段(validate、compile、package 等),然后执行 verify。你只需要调用要执行的最后一个构建阶段,也就是这种情况下的 verify。在大多数情况下,效果与 package 相同。然而,如果有集成测试,这些也将被执行。并且在 verify 阶段可以进行一些额外的检查,例如,你的代码是否按照预定义的 checkstyle 规则编写。
在构建环境中,使用以下调用来干净地构建并将工件部署到共享仓库。
Bash
mvn clean deploy在多模块场景中(即,一个或多个子项目的项目)也可以使用相同的命令。Maven 遍历每个子项目并执行 clean,然后执行 deploy(包括所有先前的构建阶段步骤)。
1.3. 构建阶段由插件目标组成
然而,尽管构建阶段负责生命周期中的特定步骤,但执行这些责任的方式可能会有所不同。这是通过声明绑定到这些构建阶段的插件目标来完成的。
插件目标代表一个特定的任务(比构建阶段更细),它有助于构建和管理项目。它可能绑定到零个或多个构建阶段。一个没有绑定到任何构建阶段的目标可以通过直接调用在构建生命周期之外执行。执行的顺序取决于调用目标和构建阶段的顺序。例如,考虑下面的命令。clean 和 package 参数是构建阶段,而 dependency:copy-dependencies 是一个目标(插件)。
Bash
mvn clean dependency:copy-dependencies package如果这个命令被执行,clean 阶段将首先被执行(意味着它将运行 clean 生命周期的所有前面的阶段,加上 clean 阶段本身),然后是 dependency:copy-dependencies 目标,最后执行 package 阶段(和 default 生命周期的所有前面的构建阶段)。
此外,如果一个目标绑定到一个或多个构建阶段,那么在所有这些阶段中都将调用该目标。
此外,一个构建阶段也可以有零个或多个目标绑定到它。如果一个构建阶段没有目标绑定到它,那么该构建阶段将不会执行。但是,如果它有一个或多个目标绑定到它,它将执行所有这些目标。
Note:在 Maven 2.0.5 及以上版本中,绑定到阶段的多个目标按照它们在 POM 中声明的顺序执行,然而不支持同一插件的多个实例。在 Maven 2.0.11 及以上版本中,同一插件的多个实例被分组在一起执行并进行排序。
1.4. 有些阶段通常不会从命令行调用
以连字符词(pre-*、post-* 或 process-*)命名的阶段通常不会直接从命令行调用。这些阶段按序构建,产生在构建之外不太有用的中间结果。
在调用 integration-test 的情况下,环境可能会处于挂起状态。代码覆盖工具如 Jacoco 和执行容器插件如 Tomcat、Cargo 和 Docker 将目标绑定到 pre-integration-test 阶段,以准备集成测试容器环境。这些插件还将目标绑定到 post-integration-test 阶段,以收集覆盖率统计信息或停用集成测试容器。
Failsafe 和代码覆盖插件将目标绑定到 integration-test 和 verify 阶段。最终结果是在 verify 阶段之后可以获得测试和覆盖率报告。如果从命令行调用 integration-test,将不会生成报告。更糟糕的是,集成测试容器环境可能会处于挂起状态,Tomcat 服务器或 Docker 实例可能仍在运行,Maven 甚至可能不会自行终止。
2. 为你的项目设置构建生命周期
构建生命周期的使用非常简单,但是当你为一个项目构建 Maven 构建时,你如何为每个构建阶段分配任务呢?
2.1. 打包
第一种,也是最常见的方式,是通过同名的 POM 元素 <packaging> 为你的项目设置打包。一些有效的打包值有 jar、war、ear 和 pom。如果没有指定打包值,它将默认为 jar。
每种打包都包含一个绑定到特定阶段的目标列表。例如,jar 打包将把以下目标绑定到 default 生命周期的构建阶段。
| 阶段 | jar 打包的 plugin: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 |
这是一个几乎标准的绑定集。然而,一些打包方式处理它们的方式不同。例如,一个纯元数据的项目(打包值为 pom)只将目标绑定到 install 和 deploy 阶段(要获取一些打包类型的目标到构建阶段绑定的完整列表,请参考生命周期参考)。
注意,要使用一些打包类型,你可能还需要在你的 POM 的 <build> 部分包含一个特定的插件,并为该插件指定 <extensions>true</extensions>。一个需要这样做的插件的例子是 Plexus 插件,它提供了 plexus-application 和 plexus-service 打包。
2.2. 插件
添加目标到阶段的第二种方式是在你的项目中配置插件。插件是为 Maven 提供目标的工件。此外,一个插件可能有一个或多个目标,其中每个目标代表该插件的一种能力。例如,编译器插件有两个目标:compile 和 testCompile。前者编译你的主代码的源代码,而后者编译你的测试代码的源代码。
如你将在后面的部分看到,插件可以包含指示将目标绑定到哪个生命周期阶段的信息。注意,仅添加插件本身的信息是不够的 —— 你还必须指定你想要作为构建的一部分运行的目标。
配置的目标将被添加到已经从选定的打包绑定到生命周期的目标中。如果有多个目标绑定到一个特定的阶段,使用的顺序是那些来自打包的目标首先被执行,然后是在 POM 中配置的目标。注意,你可以使用 <executions> 元素来更好地控制特定目标的顺序。
例如,Modello 插件默认将其目标 modello:java 绑定到 generate-sources 阶段(注意:modello:java 目标生成 Java 源代码)。所以,要使用 Modello 插件并让它从模型生成源代码并将其纳入构建,你需要在你的 POM 的 <build> 的 <plugins> 部分添加以下内容:
XML
<plugin>
<groupId>org.codehaus.modello</groupId>
<artifactId>modello-maven-plugin</artifactId>
<version>1.8.1</version>
<executions>
<execution>
<configuration>
<models>
<model>src/main/mdo/maven.mdo</model>
</models>
<version>4.0.0</version>
</configuration>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
</plugin>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
你可能会想知道为什么有 <executions> 元素。这是为了在需要的时候可以用不同的配置运行同一个目标多次。单独的 execution 也可以被赋予一个 ID,这样在继承或应用配置文件时,你可以控制目标配置是合并还是转变为额外的 execution。
当给出多个匹配特定阶段的 execution 时,它们将按照 POM 中指定的顺序执行,先执行继承的 execution。
现在,在 modello:java 的情况下,它只在 generate-sources 阶段有意义。但是,有些目标可以在多个阶段中使用,并且可能没有合理的默认值。对于这些,你可以自己指定阶段。例如,假设你有一个目标 display:time,它将当前时间回显到命令行,你希望它在 process-test-resources 阶段运行,以指示测试何时开始。这会像这样配置:
XML
<plugin>
<groupId>com.mycompany.example</groupId>
<artifactId>display-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<phase>process-test-resources</phase>
<goals>
<goal>time</goal>
</goals>
</execution>
</executions>
</plugin>1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
3. 生命周期参考
以下列出了 default、clean 和 site 生命周期的所有构建阶段,这些阶段将按照给定的顺序执行,直到指定的阶段为止。
3.1. clean 生命周期
| 阶段 | 描述 |
|---|---|
pre-clean | 执行实际项目清理之前所需的流程 |
clean | 删除由上一次构建生成的所有文件 |
post-clean | 执行完成项目清理所需的流程 |
3.2. default 生命周期
| 阶段 | 描述 |
|---|---|
validate | 验证项目是否正确,所有必要的信息是否可用 |
initialize | 初始化构建状态,例如设置属性或创建目录 |
generate-sources | 生成包含在编译中的任何源代码 |
process-sources | 处理源代码,例如过滤任何值 |
generate-resources | 生成包含在包中的资源 |
process-resources | 将资源复制并处理到目标目录,准备打包 |
compile | 编译项目的源代码 |
process-classes | 对编译后生成的文件进行后处理,例如对 Java 类进行字节码增强 |
generate-test-sources | 生成包含在编译中的任何测试源代码 |
process-test-sources | 处理测试源代码,例如过滤任何值 |
generate-test-resources | 创建测试资源 |
process-test-resources | 将资源复制并处理到测试目标目录 |
test-compile | 将测试源代码编译到测试目标目录 |
process-test-classes | 对测试编译后生成的文件进行后处理,例如对 Java 类进行字节码增强 |
test | 使用适当的单元测试框架运行测试。这些测试不应要求代码被打包或部署 |
prepare-package | 在实际打包之前执行任何必要的操作以准备包。这通常会导致包的未打包、处理过的版本 |
package | 将编译后的代码打包成其可分发的格式,例如 JAR |
pre-integration-test | 执行在执行集成测试之前所需的操作。这可能涉及诸如设置所需环境之类的事情 |
integration-test | 如果需要,将包处理并部署到可以运行集成测试的环境中 |
post-integration-test | 执行集成测试执行后所需的操作。这可能包括清理环境 |
verify | 运行任何检查以验证包是否有效并满足质量标准 |
install | 将包安装到本地仓库,供本地其他项目作为依赖项使用 |
deploy | 在集成或发布环境中完成,将最终包复制到远程仓库,与其他开发人员和项目共享 |
3.3. site 生命周期
| 阶段 | 描述 |
|---|---|
pre-site | 执行实际项目站点生成之前所需的流程 |
site | 生成项目的站点文档 |
post-site | 执行完成站点生成所需的流程,并准备进行站点部署 |
site-deploy | 将生成的站点文档部署到指定的网络服务器 |
4. 内置生命周期绑定
一些阶段默认绑定了目标。对于默认生命周期,这些绑定取决于打包值。以下是一些目标到构建阶段的绑定。
4.1. 清理生命周期绑定
| 阶段 | 插件:目标 |
|---|---|
clean | clean:clean |
4.2. 默认生命周期绑定 - 打包 ejb / ejb3 / jar / par / rar / war
| 阶段 | 插件:目标 |
|---|---|
process-resources | resources:resources |
compile | compiler:compile |
process-test-resources | resources:testResources |
test-compile | compiler:testCompile |
test | surefire:test |
package | ejb:ejb / ejb3:ejb3 / jar:jar / par:par / rar:rar / war:war |
install | install:install |
deploy | deploy:deploy |
4.3. 默认生命周期绑定 - 打包 ear
| 阶段 | 插件:目标 |
|---|---|
generate-resources | ear:generate-application-xml |
process-resources | resources:resources |
package | ear:ear |
install | install:install |
deploy | deploy:deploy |
4.4. 默认生命周期绑定 - 打包 maven-plugin
| 阶段 | 插件:目标 |
|---|---|
generate-resources | plugin:descriptor |
process-resources | resources:resources |
compile | compiler:compile |
process-test-resources | resources:testResources |
test-compile | compiler:testCompile |
test | surefire:test |
package | jar:jar & plugin:addPluginArtifactMetadata |
install | install:install |
deploy | deploy:deploy |
4.5. 默认生命周期绑定 - 打包 pom
| 阶段 | 插件:目标 |
|---|---|
package | |
install | install:install |
deploy | deploy:deploy |
4.6. site 生命周期绑定
| 阶段 | 插件:目标 |
|---|---|
site | site:site |
site-deploy | site:deploy |