maven-生命周期.png
maven-生命周期.xmind

构建生命周期的基础知识

Maven 基于一个“构建生命 周期”的中心概念,也就意味着构建和发布一个特定的工件(也就是工程)的过程已经被清晰地定义了。

有三种内置的生命周期:default,clean 和 site。default 生命周期处理处理项目部署,clean 生命周期处理项目清理,site 生命周期处理项目的站点(site)文档的创建。

实际上这些 lifecycle 只是在(比如 idea 里)对 phase 归类的时候特别有用,我们平时使用 mvn 命令的时候是无法指定这几个生命周期的。

一个构建生命周期是由多个阶段(phases)组成的

上面每个生命周期是由不同的 phase 列表组成的。一个 phase 表示一个生命周期的一个 stage(这两者有什么差别?)。

default 里 phases 的顺序大致上是是 validate -> compile -> test -> package -> verify -> install -> deploy

使用命令行

如果我们使用命令:

1
mvn install

实际上到 install 为止所有的phases 都会执行,所以我们通常只要指定执行某一个生命周期的最后一个目标 phase 就行了。

如果我们使用命令:

1
mvn clean deploy

maven 会先进行清理,然后再进行部署。如果这是一个多 module 的项目(即有多个子项目),则会遍历每个项目以执行 clean 和 deploy。

如果我们使用命令:

1
mvn clean install -Dmaven.test.skip=true

则执行清理、安装且跳过测试 phase。

每一个构建 phase 是由构建 goal 组成的

phase 下面还可以再细分,细分的单元就是 plugin goal。

plugin goal 其实是一个执行的任务(比 phase 更细粒度)一个 goal 可以和一个或者多个 phase 绑定,甚至在生命周期之外通过直接 invocation 运行。

1
mvn clean dependency:copy-dependencies package

mvn 是一级命令。

clean 和 package 是二级命令,也就是 phase。

dependency 是三级命令,也就是 plugin。

copy-dependencies差不多可以说是参数,也就是 plugin goal。

上面的命令就是执行 clean 及其前面所有的 phases 的所有 goal,单独执行 dependency 插件的 copy-dependencies goal,然后再执行 package 的所有 goal。

一个 goal 被绑定到(bound 是 bind 的过去分词形式)多个 phase,这个 goal 会被执行多遍。

设置你的项目来使用构建生命周期

如何把任务分配到构建 phases 里?

packaging

第一个方法是使用 packaging,它对应的 POM 元素是<packaging>。它的有效值分别是:jar、war、ear 和 pom(pom 也是一个 packaging 值,证明这个项目是 purely meta data)。默认值就是 jar。

packaging 有不同的值,插件的 goal 对各个 phases 的绑定就不同。

jar 的插件绑定如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<phases>
<process-resources>
org.apache.maven.plugins:maven-resources-plugin:2.6:resources
</process-resources>
<compile>
org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
</compile>
<process-test-resources>
org.apache.maven.plugins:maven-resources-plugin:2.6:testResources
</process-test-resources>
<test-compile>
org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile
</test-compile>
<test>
org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
</test>
<package>
org.apache.maven.plugins:maven-jar-plugin:2.4:jar
</package>
<install>
org.apache.maven.plugins:maven-install-plugin:2.4:install
</install>
<deploy>
org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy
</deploy>
</phases>

其他 phases 见这个《Plugin Bindings for default Lifecycle Reference》

如何控制构建的语言版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<!-- 这一行可能可以不要 -->
<maven.compiler.release>17</maven.compiler.release>
</properties>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release> <!--or <release>10</release>-->
</configuration>
</plugin>

plugins

插件是向 maven 提供 goal 的 artifact,即插件虽然自己包含很多 mojo,但它是以 artifact 的形式向外发布自己的能力(capability)的。例如,compile插件提供两个 goal:compiletestCompile(注意看,没有中间的 hyphen,所以不是 phase)。

在添加插件的时候要注意,不是只是加入一个 plugin 就万事大吉了,我们需要指定我们想要在构建的时候运行的 goal。

因为 packaging 本身也含有对插件和 goal 的绑定,所以我们要当心混合使用的时候的顺序问题。我们可以使用<execution/>来进行顺序的控制,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<plugin>
<groupId>org.codehaus.modello</groupId>
<artifactId>modello-maven-plugin</artifactId>
<version>1.8.1</version>
<!-- execution 可以包着 configuration -->
<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>

execution 里还可以指定 phases:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<plugin>
<groupId>com.mycompany.example</groupId>
<artifactId>display-maven-plugin</artifactId>
<version>1.0</version>
<executions>
<execution>
<!-- 默认的 plugin 都是有默认的 phase 属性的,但可以靠配置覆盖这些属性 -->
<phase>process-test-resources</phase>
<goals>
<goal>time</goal>
</goals>
</execution>
</executions>
</plugin>

生命周期参考

clean 生命周期的 phases

phase 含义
pre-clean 在实际的项目清理以前,需要被执行的处理过程(processes)
clean 移走前一个 build 生成的所有文件
post-clean 执行所有需要用来终结项目清理的过程

default 的 phases

phase 含义
validate 验证项目是正确的,且所有必须信息是可用的(实际上就是整个 pom 文件是 valid 的)
initialize 初始化构建状态,即设置 properties 或创建目录。也就是 properties 要在这个阶段被 inject
generate-sources 为任何编译中的inclusion(包含)生成源代码。
process-sources 处理源代码,比如过滤某些值
generate-resources 为打包的时候需要的inclusion(包含)生成资源。也就是中间资源(resources/assets)生成。
process-resources 拷贝和处理资源到目标文件夹里,为打包做准备。也就是静态资源准备完毕
compile 编译项目的源代码
process-classes 后处理编译生成的文件,比如对 Java 类进行字节码增强。也就是
generate-test-sources 为编译中的inclusion(包含)生成测试用源代码
process-test-sources 处理测试源代码,比如过滤某些值
generate-test-resources 为测试创建资源。
process-test-resources 复制和处理资源到测试目标目录
test-compile 编译测试源代码到测试目标目录
process-test-classes 对测试编译的结果进行后处理,比如进行字节码增强,需要 Maven 2.0.5 和以上版本。
test 用测试框架中合适的单元运行测试,这些测试不能要求类被打包和部署
prepare-package 进行任何实际打包前必须的准备操作
package 把编译过的远吗装进一个可发布格式,比如 JAR
pre-integration-test 进行集成测试前需要的活动,比如设置一个合适的环境
integration-test 处理和部署一个包,如果有必要的话,部署到一个集成测试可以被运行的环境里
post-integration-test 执行集成测试后需要执行的活动,比如清理环境
verify 跑一些校验,来验证包是有效的,而且满足质量标准的
install 把当前的包安装到本地仓库,这样可以作为其他项目的本地依赖
deploy 在集成或者发布环境中执行,把包拷贝到一个远程的仓库,给其他开发者和项目共享

site 的 phases

phase 含义
pre-site 执行需要在站点生成(generation)之前执行的流程
site 生成项目的站点文档
post-site 执行需要被用来终结站点生成的操作,来为站点部署做准备
site-deploy 部署站点文档到特定的 web server 里(而不是仓库里)