Chapter 10. 构建生命周期

10.1. 简介

Maven使用POM描述项目,将其建模成一些名词。POM记录了一个项目的定义:项目包含什么?需要怎样的打包类型?是否包含一个父项目?它的依赖是什么?我们已经在前面的章节展示了如何描述一个项目,但还没有介绍一种允许Maven针对这些对象进行操作的机制。在Maven中这些“动词”是由Maven插件包装的一些目标,它们绑定到一个构建生命周期的阶段中。一个Maven生命周期包含了一些有序的命名阶段:prepare-resources,compile,package,和install以及其它。有个阶段抽象了编译过程,有个阶段抽象了打包过程。而那些pre-和post-阶段可以用来注册一些必须在某些特定阶段之前或之后运行的目标。当你让Maven构建一个项目的时候,你其实是让它一步步通过那些预定义的有序的阶段,并且运行所有注册到某个特定阶段的目标。

一个构建生命周期是一组精心组织的有序的阶段,它的存在能使所有注册的目标变得有序运行。这些目标根据项目的打包类型被选择并绑定。Maven中有三种标准的生命周期:清理(clean),默认(default)(有时候也称为构建),和站点(site)。本章,我们将学习Maven如何将目标绑定到生命周期,生命周期如何自定义。你同时也会学到默认生命周期阶段的知识。

10.1.1. 清理生命周期 (clean)

第一个你将感兴趣的生命周期是Maven中最简单的生命周期。运行mvn clean将调用清理生命周期,它包含了三个生命周期阶段:

  • pre-clean

  • clean

  • post-clean

在清理生命周期中最有意思的阶段是clean阶段。Clean插件的clean目标(clean:clean)被绑定到清理生命周期中的clean阶段。目标clean:clean通过删除构建目录删除整个构建的输出。如果你没有自定义构建目录位置,那么构建目录就是定义在超级POM中的/data/hudson-temporal-data/hudson-orchestrator-home/workspace/Book-To-Production/content-zh/target。当你运行clean:clean目标的时候你并不是直接运行mvn clean:clean,你可以通过执行清理生命周期的clean阶段运行该目标。运行clean阶段能让Maven有机会执行其它可能被绑定到pre-clean阶段的目标。

例如,假设你想要在pre-clean的时候触发一个antrun:run目标任务来输出一个通知,或者需要在项目构建目录被删除之前将其归档。简单的运行clean:clean目标不会完整的执行该生命周期,但是指定clean阶段就能使用clean生命周期,并且逐个的经过生命周期阶段,直到到达clean阶段。Example 10.1, “在pre-clean阶段触发一个目标”展示了一个样例,在它的构建配置中,绑定了antrun:runpre-clean阶段,输出一个警告告诉用户项目构件即将被删除。该例中,antrun:run目标被用来执行一些随意的Ant命令来检查项目的构件。如果项目的构件将要被删除,它会打印该信息至屏幕。

Example 10.1. 在pre-clean阶段触发一个目标

<project>
  ...
  <build>
    <plugins>... <plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
      <execution>
        <id>file-exists</id>
        <phase>pre-clean</phase>
        <goals>
          <goal>run</goal>
        </goals>
        <configuration>
          <tasks>
            <!-- adds the ant-contrib tasks (if/then/else used below) -->
            <taskdef resource="net/sf/antcontrib/antcontrib.properties" />
            <available 
              file="/data/hudson-temporal-data/hudson-orchestrator-home/workspace/Book-To-Production/content-zh/target/book.jar"
              property="file.exists" value="true" />

            <if>
              <not>
                <isset property="file.exists" />
              </not>
              <then>
                <echo>No
                  book.jar to
                  delete</echo>
              </then>
              <else>
                <echo>Deleting
                  book.jar</echo>
              </else>
            </if>
          </tasks>
        </configuration>
      </execution>
    </executions>
    <dependencies>
      <dependency>
        <groupId>ant-contrib</groupId>
        <artifactId>ant-contrib</artifactId>
        <version>1.0b2</version>
      </dependency>
    </dependencies>
  </plugin>
  </plugins>
  </build> 
</project>

在带有如上构建配置的项目中运行mvn clean会生成如下的输出:


[INFO] Scanning for projects...
[INFO] ----------------------------------------------------------------------
[INFO] Building Your Project
[INFO]    task-segment: [clean]
[INFO] ----------------------------------------------------------------------
[INFO] [antrun:run {execution: file-exists}]
[INFO] Executing tasks
     [echo] Deleting your-project-1.0-SNAPSHOT.jar
[INFO] Executed tasks
[INFO] [clean:clean]
[INFO] Deleting directory ~/corp/your-project/target
[INFO] Deleting directory ~/corp/your-project/target/classes
[INFO] Deleting directory ~/corp/your-project/target/test-classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Wed Nov 08 11:46:26 CST 2006
[INFO] Final Memory: 2M/5M
[INFO] ------------------------------------------------------------------------

除了在pre-clean阶段配置Maven去运行一个目标,你也可以自定义Clean插件去删除构建输出目录以外的文件。你可以配置该插件去删除那些在fileSet中指定的文件。下面的样例配置了Clean插件,使用标准的Ant文件通配符:*和**,删除所有target-other/目录中的.class文件。

Example 10.2. 自定义Clean插件的行为

<project>
  <modelVersion>4.0.0</modelVersion>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <configuration>
          <filesets>
            <fileset>
              <directory>target-other</directory>
              <includes>
                <include>*.class</include>
              </includes>
            </fileset>
          </filesets>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>


10.1.2. 默认生命周期 (default)

大部分Maven用户将会对默认生命周期十分熟悉。它是一个软件应用程序构建过程的总体模型。第一个阶段是validate,最后一个阶段是deploy。这些默认Maven生命周期的阶段如Table 10.1, “Maven默认生命周期阶段”所示:

Table 10.1. Maven默认生命周期阶段

生命周期阶段 描述
validate 验证项目是否正确,以及所有为了完整构建必要的信息是否可用
generate-sources 生成所有需要包含在编译过程中的源代码
process-sources 处理源代码,比如过滤一些值
generate-resources 生成所有需要包含在打包过程中的资源文件
process-resources 复制并处理资源文件至目标目录,准备打包
compile 编译项目的源代码
process-classes 后处理编译生成的文件,例如对Java类进行字节码增强(bytecode enhancement)
generate-test-sources 生成所有包含在测试编译过程中的测试源码
process-test-sources 处理测试源码,比如过滤一些值
generate-test-resources 生成测试需要的资源文件
process-test-resources 复制并处理测试资源文件至测试目标目录
test-compile 编译测试源码至测试目标目录
test 使用合适的单元测试框架运行测试。这些测试应该不需要代码被打包或发布
prepare-package 在真正的打包之前,执行一些准备打包必要的操作。这通常会产生一个包的展开的处理过的版本(将会在Maven 2.1+中实现)
package 将编译好的代码打包成可分发的格式,如JARWAR,或者EAR
pre-integration-test 执行一些在集成测试运行之前需要的动作。如建立集成测试需要的环境
integration-test 如果有必要的话,处理包并发布至集成测试可以运行的环境
post-integration-test 执行一些在集成测试运行之后需要的动作。如清理集成测试环境。
verify 执行所有检查,验证包是有效的,符合质量规范
install 安装包至本地仓库,以备本地的其它项目作为依赖使用
deploy 复制最终的包至远程仓库,共享给其它开发人员和项目(通常和一次正式的发布相关)

10.1.3. 站点生命周期 (site)

Maven不仅仅能从一个项目构建软件构件,它还能为一个或者一组项目生成项目文档和报告。项目文档和站点生成有一个专有的生命周期,它包含了四个阶段:

  1. pre-site

  2. site

  3. post-site

  4. site-deploy

默认绑定到站点生命周期的目标是:

  1. site - site:site

  2. site-deploy -site:deploy

打包类型通常不更改此生命周期,因为打包类型主要和构件创建有关,和站点生成没有太大的关系。Site插件触发Doxia执行文档生成,以及执行其它报告生成插件。你可以通过运行如下命令从一个Maven项目生成一个站点:

$ mvn site

有关更多的Maven站点生成信息,查看Chapter 15, 站点生成