bboyjing's blog

Maven学习笔记二【构建生命周期】

本节来学下Maven的构建生命周期。

构建生命周期基础

Maven是以构建生命周期为核心的概念的。这意味着构建和发布特定项目的过程是明确定义的。有三个内建的构建生命周期:default、clean和site。default生命周期处理项目部署,clean生命周期处理项目清理,而site生命周期处理项目站点文档的创建。

构建生命周期的阶段

每个构建生命周期都由不同的构建阶段列表定义,其中构建阶段表示生命周期中的一个阶段。例如,default生命周期包括以下阶段:

  • validate - 验证项目是否正确,并提供所有必要的信息
  • compile - 编译项目源代码
  • test - 使用合适的单元测试框架测试编译后的源代码。这些测试不需要打包或部署代码
  • package - 将编译后的代码以其可分发的格式打包,例如JAR
  • verify - 对集成测试的结果进行检查,以确保满足质量标准
  • install -将包安装到本地存储库中,作为本地其他项目中的依赖项使用
  • deploy - 在集成或发布环境中操作,将最终包复制到远程存储库,以便与其他开发人员和项目共享

这些生命周期阶段(加上这里没有显示的其他生命周期阶段)按顺序执行,以完成default生命周期。鉴于上面的生命周期阶段,这意味着当使用default生命周期时。Maven将首先验证项目,然后将视图编译源代码,运行测试,打包二进制文件(如jar),运行集成测试方案,验证集成测试,安装验证过的包到本地存储库,然后将安装包部署到远程存储库。

命令行调用

在开发环境中,使用如下的命令构建、安装项目到本地存储库中:

1
mvn install

该命令在执行安装之前按顺序(验证、编译、打包等)执行default生命周期的每个阶段。只需要调用要执行的最后一个构建阶段,在本例中就是install

在构建环境中,使用以下调用将项目干净地构建并部署到共享存储库中:

1
mvn clean deploy

相同的命令可以在多模块场景中使用(即带有一个或多个子项目的项目)。Maven遍历每个子项目并执行clean,然后执行deploy(包括前面的所有构建阶段步骤)。

构建阶段由插件目标组成

然而,即使构建阶段负责构建生命周期中的特定步骤,它执行这些职责的方式也可能不同。这是通过声明插件目标绑定到那些构建阶段来实现的。

一个插件目标代表一个特定的任务,它有助于项目的构建和管理。它可能被绑定到零或多个构建阶段。不绑定到任何构建阶段的目标可以通过直接调用在构建生命周期之外执行。执行的顺序取决于调用目标和构建阶段的顺序。例如,如下命令,参数clean和package是构建阶段,dependency:copy-dependencies是(插件的)目标。

1
mvn clean dependency:copy-dependencies package

如果执行上述命令,clean以及其之前的阶段将首先被执行,然后执行dependency:copy-dependencies目标,最后执行package以clean和package之间的阶段。执行之后,在target目录下会生成一个dependency目录。

不从命令行调用的阶段

用连字符命名的阶段(pre-*、post-*或process-*)通常不会直接从命令行调用。这些阶段对构建进行排序,产生对构建没有用的中间结果。

设置项目的构建生命周期

构建生命周期简单好用,但是当我们构建一个项目时,是如何将任务分配到每个构建阶段的呢?

Packaging

第一种也是最常见的方法,是通过pom文件中命名的<packaging>标签来设置项目的打包。一些有效的包装值是jar、war、ear和pom。如果没有指定,它将默认为jar。

每个打包都包含要绑定到特定阶段的目标列表。例如,打jar包将绑定以下目标来构建default生命周期的各个阶段。

Phase 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打包。

Plugins

向阶段添加目标的第二种方法是在项目中配置插件。插件是为Maven提供行为目标的项目。此外,一个插件可能有一个或多个目标,其中每个目标表示该插件的功能。例如,编译器插件有两个目标:compile和testCompile。前者编译主代码的源代码,而后者编译测试代码的源代码。

插件可以包含指示将目标绑定到哪个生命周期阶段的信息。请注意,单独添加插件是不够的——还必须指定希望作为构建的一部分运行的目标。

配置的目标将被添加到选择的packaging(例如,jar)已绑定的生命周期中。如果将多个目标绑定到某个特定阶段,那么使用的顺序是先执行来自packaging的目标,然后再执行pom中配置的目标。注意,可以使用<executions>元素来获得对特定目标顺序的更多控制。

例如,Modello插件默认情况下将其目标modello:java绑定到generate-sources阶段( modello:java目标是生成源代码)。因此,要使用Modello插件并让它从模型中生成源代码并将其合并到构建中,需要添加如下插件添加到pom中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
<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>
...

该插件具体如何使用,请参照官网示例,这里就不演示了。对于对于modello:java而言,只在generate-sources阶段起作用。但有些目标可以在多个阶段使用,而且可能不存在合理的缺省值。对于这些情况,我们可以自己指定阶段。例如,假设有这样一个目标display:time,在命令行打印当前时间。希望它在process-test-resources阶段运行,以显示测试合适启动。配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
<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>
...

当然,这只是配置样例,目前没有该插件,是无法运行的。

生命周期参考

关于defaultcleansite生命周期包含的阶段参照官网列举的内容

内建的生命周期绑定

默认情况下,有些阶段的目标是与之绑定的。并且对于default生命周期,这些绑定依赖于<packaging>的值。具体的列表参照官网的列举

参考

完整的Maven生命周期定义在maven-core模块的components.xml文件中,提供参考文档

default生命周期绑定单独定义在default-bindings.xml文件中。

查看 Lifecycles ReferencePlugin Bindings for default Lifecycle Reference 以获取最新的文档