Maven——生命周期

  本章介绍Maven生命周期的概念,生命周期之所以重要,是因为我们每运行一次maven指令,本质上都是在运行生命周期的某个phase。实际使用Maven,都是命令,一种方式是直接的在cmd上执行输入的maven指令,另外一种是通过UI方式,点击某个菜单,它在底层去运行相关的指令。理解生命周期对于理解命令大有帮助。

本章主要分为四个部分

  1. 基本的概念
  2. 内置生命周期
  3. 自定义生命周期,编写HelloWorld插件
  4. 扩展内置的生命周期

1、概念

  在介绍上述四个部分之前,需要理解lifeCycle(生命周期),plugin(插件)的概念。

1.1  lifecycle & phase

  引用原著中的定义:

A Maven build lifecycle consists of a set of well-defined phases, Each phase groups a set of goals defined by Maven plugins and the lifecycle defines the order of execution

这段话有三个含义。

第一个含义,lifecycle与phase之间的关系,lifecycle是由一组预定义的phase组成的。

  第二个含义,phase与plugin之间的关系,phase与goals是一对多的关系,plugin是由一到多个goal组成的。

  第三个含义,lifecycle定义了phase的执行顺序。

1.2   plugin & goal

  引用原著中对plugin的定义:

A Maven plugin is a collection of goals where each goal is responsible for performing a specific action

它是goals的集合,类似于Controller与methods之间的关系。

1.3  phase 与 goal的关系

 

   类比Web应用,后端Controller提供了一组接口,它类似于goal的作用,而前端提供了一组按钮,它类似于phase的作用。

  当我们点击按钮时,真正运行的是后台Controller中的代码和JS的代码。与此类似,当我们运行mvn指令时,真正运行的是plugin中goal的代码,controller与按钮之间建立关系是通过ajax请求建立的,phase与goal建立关系是通过子标签建立的。

  当按钮没有与后台建立关系,自然点击按钮则不会有任何效果。phase也是一样的,若phase与goal之间没有建立关系,执行指令没有任何效果。

  区别在于前端按钮与接口的关系通常是一对一,而且有什么参数之类的。而maven中phase与goal之间的关系是1对多的。

  理解这些之后,再介绍内置的maven生命周期会很容易理解。

2、内置生命周期

2.1 clean

  2.1.1 图片

  

2.1.2  phases

  clean生命周期有三个phase, pre-clean, clean, post-clean。类似于spring拦截器的那个方法。

  pre-clean在清理之前运行

  clean运行清理的逻辑。

  post-clean在清理之后运行

  执行mvn help:describe -Dcmd=clean,查看clean的phase。结果如下:

'clean' is a phase within the 'clean' lifecycle, which has the following phases: 
* pre-clean: Not defined
* clean: org.apache.maven.plugins:maven-clean-plugin:2.5:clean
* post-clean: Not defined

  可以清晰的看到,pre-clean, post-clean没有goal与之关联。clean(phase)与2.5版本的maven-clean-plugin的clean(goal)关联。

  2.1.3  插件

  执行mvn help:describe -Dplugin=clean,查看clean插件。结果如下:

Name: Apache Maven Clean Plugin
Description: The Maven Clean Plugin is a plugin that removes files generated at build-time in a project's directory.
Group Id: org.apache.maven.plugins
Artifact Id: maven-clean-plugin
Version: 3.1.0
Goal Prefix: clean

This plugin has 2 goals:

clean:clean
  Description: Goal which cleans the build.This attempts to clean a project's working directory of the files that were generated at build-time. By default, it discovers and deletes the  directories configured in project.build.directory,project.build.outputDirectory, project.build.testOutputDirectory, and    project.reporting.outputDirectory.
    
    Files outside the default may also be included in the deletion by
    configuring the filesets tag.

clean:help
  Description: Display help information on maven-clean-plugin.
    Call mvn clean:help -Ddetail=true -Dgoal=<goal-name> to display parameter
    details.

For more information, run 'mvn help:describe [...] -Ddetail'

  可以看到clean插件有两个goal,分别是clean和help,运行它们的命令分别是mvn clean:clean, mvn clean:help。

  clean插件的clean删除以下四个目录

  1. project.build.directory:编译的根目录,通常是target
  2. project.build.outputDirectory:编译之后的字节码目录,通常是target/classes
  3. project.build.testOutputDirectory:测试代码编译之后的字节码目录,通常是target/test-classes
  4. project.reporting.outputDirectory: 项目报告的存放目录,通常是target/site。

  2.1.4   指令(mvn clean)

  因为clean名称很重复,所以clean生命周期时,比较容易混淆。Lifecycle,phase,pluginName, goal它们四个的名称都是clean。

  问题1:执行mvn clean究竟是在执行什么?

  答:它在执行clean生命周期,会依次执行pre-clean,clean,post-clean,由于只有clean有对应的goal,所以本质上只执行了clean插件的clean。

  问题2:指令执行的方式有哪几种?

  答:有三种,执行生命周期,例如mvn clean。执行生命周期的某个phase,例如mvn clean:clean。执行插件的某个goal,例如mvn clean:help。

2.2  default

2.2.1   phases

  default有23个,它大致分为五个阶段。准备,编译资源,编译测试代码并运行测试代码,打包,部署。

  执行mvn help:describe -Dcmd=validate,显示的结果如下:

It is a part of the lifecycle for the POM packaging 'jar'. This lifecycle includes the following phases:
* validate: Not defined
* initialize: Not defined
* generate-sources: Not defined
* process-sources: Not defined
* generate-resources: Not defined
* process-resources: org.apache.maven.plugins:maven-resources-
plugin:2.6:resources
* compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
* process-classes: Not defined
* generate-test-sources: Not defined
* process-test-sources: Not defined
* generate-test-resources: Not defined
* process-test-resources: org.apache.maven.plugins:maven-resources-
plugin:2.6:testResources
* test-compile: org.apache.maven.plugins:maven-compiler-
plugin:3.1:testCompile
* process-test-classes: Not defined
* test: org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
* prepare-package: Not defined
* package: org.apache.maven.plugins:maven-jar-plugin:2.4:jar
* pre-integration-test: Not defined
* integration-test: Not defined
* post-integration-test: Not defined
* verify: Not defined
* install: org.apache.maven.plugins:maven-install-plugin:2.4:install
* deploy: org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy

  上述列出了23个phase,以及它们对应的goal。

  2.2.1.1    准备

  它包含两个phase

  validate,校验pom文件的正确性以及完整性。它没有与之对应的goal,执行mvn default:validate没有任何效果。通常是IDE去校验pom文件的正确性。

  initialize,初始化目录结构,获取必要的属性。它也没有对应的goal。

  可以执行mvn validate -X > result.txt,去查看命令的运行日志。二者都没有任何效果。

  2.2.1.2  编译源代码

  它包含六个phase

  generate-sources,生成源代码。没有对应的goal

  process-sources,处理源代码。没有对应的goal

  generate-resources,生成配置文件。没有对应的goal

  process-resources,处理配置文件,创建编译输出目录,将resources配置文件拷贝到对应的目录下。有对应的goal。

  compile: 编译源代码,并拷贝到对应的输出目录。有对应的goal,

  process-classes:处理编译源代码之后的字节文件,没有对应的goal。

  执行mvn compile -X >result.txt,去查看命令的运行日志,在target目录下去查看,发现只生成了classes和配置文件。

  2.2.1.3     编译测试代码

  与编译源代码的phase功能和数量基本相同,名称中多了test。

  generate-test-resources:生成测试代码。没有对应的goal

  process-test-resources:处理测试代码。没有对应的goal

  generate-test-resources:生成测试配置文件。没有对应的goal

  process-test-resources:处理测试配置文件,创建编译输出目录,若已存在不创建,将test目录下的resources配置文件拷贝到对应的目录下。有对应的goal。

  test-compile:编译测试代码,并拷贝到对应的输出目录。有对应的goal。

  process-test-classes:处理并编译测试代码之后的字节文件,没有对应的goal。

  执行mvn test-compile -x > result.txt,去查看命令的运行日志,在target目录下去查看,发现只生成了测试代码的字节码和配置文件(test-classes目录)。

  2.2.1.4     打包

  它有三个phase

  pre-package:在打包之前运行

  package:打包的逻辑,它对应maven-jar-plugins,执行此命令,会生成jar包。

  post-package:在打包之后运行。

  执行mvn package -x > result.txt,查看运行的日志。在target目录下去查看,会发现生成了jar包。

  Jar包默认的名字是name + version。可以通过配置build | finalName标签设置Jar的名称。

  2.2.1.5     集成测试

  2.2.1.6     部署

  部署有三个phase

  verify:校验package是否正确,没有对应的goal

  install:在本地仓库部署,部署完成之后,可以在本地版本库查看到对应的目录,它对应的插件是maven-install-plugin。

  deploy:在远程仓库部署,部署完成之后,可以在远程仓库上查看。它对应的插件是maven-deploy-plugin。使用前需要配置远程仓库。

  执行git install -X > result.txt。查看日志,在本地版本库可以查看到相应的目录结构,例如项目group Id为com.test,artifactId为sample,也可以在本地版本库中找到com/test/sample目录结构,查看目录下的内容。

2.3  site

2.3.1   图片

  

2.3.2   phases

  site是用于生成项目报告的,它有pre-site,site, post-site, site-deploy四个phase。

  pre-site在生成报告之前执行

  site执行报告的逻辑

  post-site在生成报告之后执行

  site-deploy将生成的报告拷贝到项目Jar或war包中。

  执行mvn help:describe -Dcmd=site,运行结果如下:

'site' is a phase within the 'site' lifecycle, which has the following phases: 
* pre-site: Not defined
* site: org.apache.maven.plugins:maven-site-plugin:3.3:site
* post-site: Not defined
* site-deploy: org.apache.maven.plugins:maven-site-plugin:3.3:deploy

  只有site,site-deploy有对应的goal,它们存在于maven-site-plugin中,版本是3.3。

  2.3.3   插件

  执行mvn help:describe -Dplugin=site,运行结果会发现它有九个goal。

  1. attach-descriptor:添加site.xml配置文件,
  2. deploy:把生成的报告部署到远程仓库。
  3. effective-site:显示site.xml文件的内容。
  4.  help:显示site插件的用法
  5. jar:把生成的报告打包到jar中
  6. run:启动web服务,它可以查看生成的报告。
  7. site:执行生成报告的逻辑过程
  8. stage:
  9. stage-deploy:

2.3.4   指令

  执行mvn site相关的指令有两类,第一类是插件:goal,例如执行mvn site:help。第二类是生命周期:phase,这种情况下生命周期可以省略,例如执行mvn site:site,mvn pre-site。

  pre-site,post-site没有对应的goal,没有任何结果。

3、生命周期与phase

  建立生命周期与phase之间的关系,是通过maven-core-version.jar中的META-INF/plexus/components.xml定义的,它的格式如下:

<component>
  <role>org.apache.maven.lifecycle.Lifecycle</role>
 <implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
  <role-hint>default</role-hint>
  <configuration>
    <id>default</id>    
    <phases>
      <!-- 1到多个phase -->
      <phase>validate</phase>
    </phases>
  </configuration>
</component>

  role指定component的类型,以及它暴露在外的接口类,必须是org.apache.maven.lifecycle.Lifecycle。

  implementation指定接口的具体实现类。

  role和role-hint是联合主键,唯一标识一个component元素,当role相同时,必须指定role-hint,通常与Lifecycle同名。

  id指定Lifecycle的名称

  phases指定一个到多个phase,例如default生命周期指定23个phase。

3.1  示例

<component>
  <role>org.apache.maven.lifecycle.Lifecycle</role>
  <implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
  <role-hint>clean</role-hint>
  <configuration>
    <id>clean</id>
    
    <phases>
      <phase>pre-clean</phase>
      <phase>clean</phase>
      <phase>post-clean</phase>
    </phases>
    <default-phases>
      <clean>
        org.apache.maven.plugins:maven-clean-plugin:2.5:clean
      </clean>
    </default-phases>
    
  </configuration>
</component>

  default-phases用于建立phase与goal之间的关系。查看default生命周期时看到没有goal与之关联。建立default生命周期phase与goal关系的步骤如下:

  1. 第一步,在项目中配置pom.xml,在build中定义插件XX_plugin。
  2. 第二步,XX_plugin中的components.xml中定义了phase与goal之间的关系,不同的plugin,phase与goal之间的关系是不同的。

4、HelloWorld插件示例

  演示Hello World插件编写的过程,并验证。具体步骤如下:

  第一步:创建Maven plugin项目,与创建普通的Maven项目步骤相同,区别在于选择archetype时,选择maven-archetype-mojo。

  第二步:创建src/main/resources资源文件夹,在下面创建META-INF文件夹,创建components.xml,它用于定义插件与goal之间的关系。示例如下:

<?xml version="1.0" encoding="UTF-8"?>
<component-set>
    <components>
        <component>
            <role>org.apache.maven.lifecycle.Lifecycle</role>
            <role-hint>HelloWorld</role-hint>
           <implementation>org.apache.maven.lifecycle.Lifecycle</implementation>
            <configuration>
                <id>hello_world</id>
                <phases>
                    <phase>hello_world</phase>
                </phases>
                <default-phases>
                    <hello_world>
                        org.example:HelloWorld:hello_world
                    </hello_world>
                </default-phases>
            </configuration>
        </component>
    </components>
</component-set>

  它与其他生命周期的格式基本相同,default-phases下的格式为<goal></goal>,其中的值为groupId:artifactId:goal文档注释。

  第三步,创建HelloWorldMojo对象,继承AbstractMojo, 实现execute方法,本示例中只是打印一句”Hello Maven World”, 它需要在文档注解中添加@goal。代码如下:

/**
 * @goal hello_world
 * @requiresProject false
 */
public class HelloWorldMojo extends AbstractMojo {
    public void execute() throws MojoExecutionException, MojoFailureException {
        System.out.println("Hello Maven World");
    }
}

  第四步,打包,执行mvn clean install。它会安装在你本地的maven仓库中

  第五步,创建任意maven项目,引入插件,代码如下:

<build>
    <plugins>
        <plugin>
            <groupId>org.example</groupId>
            <artifactId>HelloWorld</artifactId>
            <version>1.0-SNAPSHOT</version>
            <extensions>true</extensions>
        </plugin>
    <plugins>
</build>

  第六步,验证,执行mvn hello_world,结果如下:

[INFO] org.apache.maven.cli.event.ExecutionEventLogger - --- HelloWorld:1.0-SNAPSHOT:hello_world (default-hello_world) @ jackson-demo ---
Hello Maven World
[INFO] org.apache.maven.cli.event.ExecutionEventLogger - ------------------------------------------------------------------------

  可以看到插件已正常执行成功。

  关键点

  1.   XXMojo与@goal主键建立关系,@goal注解与goal建立关系

  2.   项目的role定义的是org.apache.maven.lifecycle.Lifecycle,所以可以直接执行mvn goal, 否则它就只是一个普通的插件,执行时格式为mvn pluginId:goal。pluginId格式为groupId:artifactId

  3.   plugin与goal是一对多的关系。goal与@goal注解是一对多的关系,多个时使用逗号分隔。@goal与XXMojo是一对一的关系。

  厘清生命周期,phase,plugin,goal四者之间的关系是本章的核心知识点。

posted @ 2021-03-02 14:29  蜗牛旅行1899  阅读(153)  评论(0编辑  收藏  举报