代码改变世界

介绍maven构建的生命周期

2017-08-29 18:25 轩脉刃 阅读(...) 评论(...) 编辑 收藏

介绍maven构建的生命周期

这篇是 https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html 的译文。

构建生命周期的基础知识

构建的生命周期是maven的最核心概念。它的意思就是构建和发布某个特定的artifact(project)的每个阶段是否清晰定义。

对想要构建一个project的开发人员来说,只需要掌握非常少的命令,就可以编译一个maven的项目,pom会保证会生成我们希望的产出结果。

有三个内置的构建周期:default,clean 和site。default周期处理项目的部署。clean周期处理项目的清理。site周期创建项目的站点文档。

构建的生命周期由阶段组成

每个生命周期都由一些不同的构建阶段组成。每个构建阶段都是生命周期的一个步骤。

例如,default生命周期由下面的阶段组成:

  • validate - 验证项目是否正确,并且所有必要的信息是否有效
  • compile - 编译项目的代码
  • test - 使用合适的单元测试框架测试源码。这些测试代码并不要求打包或者部署
  • package - 获取编译后的代码,并且把它们打成可派发的格式,比如JAR.
  • verify - 运行集成测试,以确保项目符合质量标准
  • install - 安装包到本地的repository中,以便其他项目可以依赖这个项目。
  • deploy - 在构建的结束阶段,把最终包上传到远端的repository中,以便其他的项目和开发者可以使用。

这些构建周期的各个步骤是用来顺序执行,以便完成default的生命周期。(当然其他的生命周期的步骤还没有介绍)。这就意味着,一旦使用了default生命周期,maven会首先验证项目,然后编译代码,跑单元测试,打包二进制文件,运行集成测试,验证集成测试,安装验证后的包到本地仓库,然后部署到远端仓库。

使用命令行调用

在开发环境,使用下面的命令构建和安装项目到本地仓库

mvn install

这个命令执行default生命周期中install阶段及之前的阶段(比如validate,compile,package等)。就是说,你只需要调用最后一个需要你执行的阶段就能执行这个阶段之前的命令了。

在构建环境,使用下面的命令就能清空构建发布在共享仓库中的项目。

mvn clean deploy

在多模块场景,maven进入到每个子项目并且执行clean,然后执行deploy。

一个构建的过程是由插件的目标组成

虽然一个构建过程是为构建生命周期的某个阶段负责,但是,实现这个阶段的方法有多种多样。这些方法是由绑定再这些编译阶段的插件的目标来实现的。

一个插件的目标代表一个用于构建和管理项目的任务(任务的概念比构建过程更为精细)。一个任务可以被绑定在零个或者多个构建过程上。没有被绑定在任何构建过程的目标也可以被直接调用。执行的顺序由目标和构建过程调用的顺序来定。例如,下面的命令。clean和package是构建过程,dependency:copy-dependencies是一个插件的目标。

mvn clean dependency:copy-dependencies package

执行这个命令,clean构建过程会被执行(意味着它执行clean构建过程之前的所有过程),然后dependency:copy-dependencies目标会被执行,最后,执行package构建过程(及前面所有的构建过程)。

如果一个目标绑定在一个或者多个构建阶段,这个目标会被所有构建阶段调用。

换句话说,一个构建阶段可以由零个或者多个目标绑定。如果一个构建阶段没有目标绑定,那么这个构建阶段就不会执行。但是一旦有一个或者多个目标绑定,它就会执行这些目标。
(注意:在Maven 2.0.5及之上,一个构建阶段的多个目标的执行顺序,是和这些目标在POM中声明的顺序一致的。但是,多个相同的插件是不允许的。在Maven2.0.11及以上版本,要是定义了多个相同插件,他们会被分组并且一起执行。)

一些构建阶段一般不会通过命令行进行调用

一些由复合词(pre-*, post-*, process-*)组成的构建阶段通常不会由命令行直接调用。这些构建过程连接整个构建流程,产生不被外部使用的中间结果。例如调用integration-test阶段,整个环境会停留在悬挂状态。

代码覆盖工具,例如Jacoco,执行容器插件,例如Tomcat,Cargo和Docker把目标绑定在pre-integration-test阶段,用于准备测试的容器环境。这些插件也绑定在post-integration-test阶段,用于收集覆盖率的统计,或者回收测试容器。

故障保护和代码覆盖插件绑定目标在integration-test和verify阶段。最终的结果就是在verify阶段之后生成可用的测试和代码覆盖率报告。如果integration-test由命令行调用,就不会生成任何的报告。更糟糕的是,迁移测试的容器环境就会停留在悬挂状态。Tomcat服务和Docker实例就会一直运行,maven不会自己终止。

使用构建生命周期来搭建项目

构建的生命周期是很容易使用的。但是具体当我们考虑使用maven构建一个项目的时候,如何为每个构建过程指定任务呢?

Packaging

首先,最通用的方法,通过POM中的元素为你的项目设置打包方式。一些可用的打包的值为jar, war, ear, 和pom。如果没有设置packing的值,默认为jar。

每个packaging会由一些特定的目标绑定在特定的任务中,比如,jar打包方式会绑定下面的目标在默认的生命周期中。

上图差不多就是基本的绑定设置。但是一些打包方式是不一样的设置。例如,纯元项目的打包方式(pom)只绑定了install和deploy构建阶段。

注意,除了默认的,一些额外的打包方式也是可以额外获取。你可以使用pom文件的标签来引入一个特定的插件,并且指定true。比如Plexus插件提供plexus-application和plexus-service打包方式。

Plugins

第二种把目标增加到构建阶段的方法是在你的项目中配置插件。插件就是提供目标给maven的项目。或者说,插件可以有一个或者多个目标,每个目标代表插件的一种能力。例如,Compiler插件有两个目标:compile和testCompile。前者编译你的主代码,后者编译你的测试代码。

在后面的章节你会看到,插件包含希望在什么构建阶段插入目标的信息。注意,插件自己并没有这个信息-你必须指定你想要在哪个编译阶段使用这个目标。

目标可以配置到那些已经被Packaging绑定的构建阶段中。如果多个目标绑定到一个特定阶段,执行的顺序是,先执行packaging中的目标,再执行配置文件POM配置的目标。注意,你可以通过来控制某些特定目标的执行顺序。

例如,Modello插件会将modello:java目标绑定到generate-source阶段(注意:modello:java目标会生成java代码)。所以,使用Modello插件并且让它生成代码并且将代码加入到build阶段,你需要加下面的

...
 <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>
...

你也许会很好奇为什么标签存在。这样你就可以根据不同的配置文件执行多次相同的目标。每个excuteion可以配置一个唯一的ID,在继承或者应用权限阶段,你可以控制是否合并目标配置文件,还是作为一个额外的执行。

当多个executions被配置给一个单独的过程,它们会按照POM中配置的中的顺序执行。

例如,modello:java,它只在generate-source构建阶段生效。但是一些目标却会在一个或者多个构建阶段执行,并且这些目标并不强制要求按照默认阶段执行。对这些,你就需要自己来配置了。例如,你有一个目标display:time,这个目标是打印当前时间到控制台,如果你希望它在process-test-resources阶段执行,以便告知什么时候测试开始执行,你就需要配置如下:

...
 <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>
...

生命周期相关参考

下面是default, clean 和site生命周期的所有构建阶段,按照下文所示的顺序执行。

clean生命周期

  • pre-clean: execute processes needed prior to the actual project cleaning
  • clean: remove all files generated by the previous build
  • post-clean: execute processes needed to finalize the project cleaning

default生命周期

  • validate: validate the project is correct and all necessary information is available.
  • initialize: initialize build state, e.g. set properties or create directories.
  • generate-sources: generate any source code for inclusion in compilation.
  • process-sources: process the source code, for example to filter any values.
  • generate-resources: generate resources for inclusion in the package.
  • process-resources: copy and process the resources into the destination directory, ready for packaging.
  • compile: compile the source code of the project.
  • process-classes: post-process the generated files from compilation, for example to do bytecode enhancement on Java classes.
  • generate-test-sources: generate any test source code for inclusion in compilation.
  • process-test-sources: process the test source code, for example to filter any values.
  • generate-test-resources: create resources for testing.
  • process-test-resources: copy and process the resources into the test destination directory.
  • test-compile: compile the test source code into the test destination directory
  • process-test-classes: post-process the generated files from test compilation, for example to do bytecode enhancement on Java classes. For Maven 2.0.5 and above.
  • test: run tests using a suitable unit testing framework. These tests should not require the code be packaged or deployed.
  • prepare-package: perform any operations necessary to prepare a package before the actual packaging. This often results in an unpacked, processed version of the package. (Maven 2.1 and above)
  • package: take the compiled code and package it in its distributable format, such as a JAR.
  • pre-integration-test: perform actions required before integration tests are executed. This may involve things such as setting up the required environment.
  • integration-test: process and deploy the package if necessary into an environment where integration tests can be run.
  • post-integration-test: perform actions required after integration tests have been executed. This may including cleaning up the environment.
  • verify: run any checks to verify the package is valid and meets quality criteria.
  • install: install the package into the local repository, for use as a dependency in other projects locally.
  • deploy: done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects.

site生命周期

  • pre-site: execute processes needed prior to the actual project site generation
  • site: generate the project's site documentation
  • post-site: execute processes needed to finalize the site generation, and to prepare for site deployment
  • site-deploy: deploy the generated site documentation to the specified web server

内置的生命周期绑定目标

一些生命周期已经绑定了一些目标。这些默认的生命周期,依赖packaging值不同有不同的目标。下面是一些构建阶段的目标:

Clean 生命周期绑定

Default 生命周期 - Packaging值为 ejb / ejb3 / jar / par / rar / war

Default 生命周期 - Packaging值为 ear

Default 生命周期 - Packaging值为 maven-plugin

Default 生命周期 - Packaging值为 pom

Site 生命周期绑定

参考

完整的Maven生命周期是在maven-core模块的components.xml文件中定义,相关查看文档

Maven2.x中,默认的生命周期绑定的目标描述是在components.xml,但在Maven3.x中,是在单独的default-bindings.xml 文件中配置的。