5. maven的生命周期和插件(一)

1. 生命周期与插件机制

  • 由于使用了高度集成的IDE,我们对一个Java项目的构建过程,能直观接触的有编译、测试、打包、部署等步骤。
  • 这些步骤,要么是手工操作,要么通过脚本实现。
  • 例如,使用脚本实现项目的构建,换一个项目,脚本一般都需要重新编写,可移植性很差。
  • 针对这样的情况,maven提出了生命周期和插件机制。

1.1 概述

  • 生命周期是对项目构建的各个步骤的抽象。同时,它还定义了构建步骤之间的次序。例如,测试之前必须先编译。
  • 生命周期本身不做任何的实际工作,实际的工作都是由插件完成。例如,代码的编译有对应的编译插件。
  • 每个构建步骤可以绑定一个或多个插件,maven为大多数构建步骤绑定了默认插件,也支持用户为构建步骤配置插件,甚至可以编写插件。

1.2 生命周期和插件机制带来的好处

  • 绑定默认的插件,使得maven项目有一致的构建标准。
  • 同时,默认插件还简化了实际项目的构建。因为,用户不需要学习如何绑定插件,使用默认插件即可。
  • 支持配置或编写插件,扩展了maven项目构建的空间。

2. 三套生命周期

  • maven拥有三套相互独立的生命周期:cleandefaultsite,分别对应项目的清理、真正构建时的所有步骤(如编译、测试、部署)、项目站点的生成。
  • 每个生命周期都包含多个阶段(phase),这些阶段是前后依赖的。
  • 例如,生命周期clean,包含pre-cleancleanpost-clean三个阶段,执行clean阶段,会先执行pre-clean,而非只执行clean

2.1 clean生命周期

  • pre-clean:执行一些清理前需要完成的工作
  • clean: 清理上一次构建生成的文件
  • post-clean:执行一些清理后需要完成的工作

2.2 default生命周期

  • 内容比较多,挑重点说:顺序大致为处理主资源、编译主代码、处理测试资源、编译测试代码、测试、打包、安装和部署

  • 其中,process-resources:将src/main/resources目录内的内容进行变量替换等工作后,复制到项目输出的主classpath目录(target/classes)中。

    这解释了为啥,我通过如下代码获取yaml文件的路径时,发现是target/classes,而非src/main/resources。明明我的yaml文件是放在src/main/resources目录的
    书中说,这是process-sources,顾名思义和查资料,我发现书中说的不对 😂

    String path = YamlUtils.class.getClassLoader().getResource("xx.yaml").getPath()
    
  • compile:编译主代码,即编译src/main/java目录下的代码,并输出到主classpath目录(target/classes)中。

  • 对应的,process-test-resources的输出目录变成了target/test-classestest-compile的输出目录变成了target/test-classes

  • 剩下的就是testpackageinstall

2.3 site生命周期

  • 包含pre-sitesitepost-sitesite-deploy三个节点

2.4 生命周期与maven命令

  • mvn clean对应clean生命周期的clean阶段
  • mvn test对应default生命周期的test阶段
  • mvn clean install对应clean生命周期的clean阶段和default生命周期的install阶段
  • 从上面的例子可以看出,常用的maven命令都是基于生命周期的某些阶段简单组合而成

3. 插件目标与插件绑定

3.1 插件目标

  • 为了复用插件,一个插件往往能完成多个任务。也就是说一个插件往往具有多个功能。
  • 例如,之前用过mvn dependency:xxx去获取、分析项目的依赖,这些功能都集中于一个插件maven-dependency-plugin
  • 我们将插件中的每个功能称为插件目标,通过插件名关键字:插件目标,便可以在maven命令中使用插件目标。这是插件目标的通用写法。
  • 例如,maven-compiler-plugin的插件名关键字为compiler,其包含一个插件目标compile。因此,该插件目标的通用写法为compiler:compile

3.2 插件绑定

  • maven的生命周期插件相互绑定,实质上是生命周期阶段插件目标的相互绑定。
  • 例如,maven-compiler-plugin插件的compile功能与default生命周期的compile阶段相互绑定,通过调用插件的compile功能就能完成代码的编译。

3.3 自定义插件绑定

  • default生命周期中的有一个叫做verify的阶段,通过如下配置可以将maven-source-pluginjar-no-fork功能绑定,从而可以创建项目的源码jar包。

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-source-plugin</artifactId>
        <version>3.0.1</version>
        <executions>
            <!-- 通过execution子元素为生命周期阶段配置插件目标-->
            <execution>
                <!-- 任务名,可以理解成是绑定关系的id-->
                <id>verify-bind</id>
                <!-- 生命周期阶段-->
                <phase>verify</phase>
                <goals>
                    <!-- 插件目标-->
                    <goal>jar-no-fork</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    
  • 执行mvn verify命令,可以触发default生命周期的verify阶段,该阶段完成的实际任务是将项目源代码打包。

    • maven-source-plugin:3.0.1:jar-no-fork是插件和插件目标

    • verify-bind是插件绑定关系的id,书上数这是任务id。

    • 通过插件绑定,生成了项目源码的jar包:jianzhioffer-1.0-SNAPSHOT-sources.jar

      [INFO] --- maven-source-plugin:3.0.1:jar-no-fork (verify-bind) @ jianzhioffer ---
      [INFO] Building jar: /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT-sources.jar
      

3.4 maven的默认插件绑定

  • 为了降低用户的使用门槛,maven为一些主要的生命周期阶段绑定了很多插件目标,只需要简单的执行maven命令,就可以完成一些构建任务。

  • clean生命周期的clean阶段与maven-clean-pluginclean插件目标默认绑定

  • default生命周期的默认绑定如下表所示:

    生命周期阶段插件插件目标执行的任务
    process-resourcesmaven-resources-pluginresources复制主资源文件到主输出目录
    compilemaven-compiler-plugincompile编译主代码至主输出目录
    process-test-resourcesmaven-resources-plugintestResources复制测试资源文件到测试输出目录
    test-compilemaven-compiler-plugintestCompile编译测试代码至测试输出目录
    testmaven-surefire-plugintest执行单元测试
    packagemaven-jar-pluginjar创建项目jar包
    installmaven-install-plugininstall将项目构件安装到本地仓库
    deploymaven-deloy-plugindeploy将项目构件部署到远程仓库
  • site生命周期的site阶段与maven-site-pluginsite插件目标默认绑定;site-deploy阶段与maven-site-plugindeploy插件目标默认绑定

  • 通过执行mvn clean install命令,我们可以看到clean阶段对应的默认插件目标,以及defaul生命周期到install阶段对应的所有默认插件目标。

    # clean阶段
    [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ jianzhioffer ---
    [INFO] Deleting /Users/xxxx/IdeaProjects/JianzhiOffer/target
    # process-resources阶段
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ jianzhioffer ---
    [INFO] Copying 0 resource
    # compile阶段
    [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ jianzhioffer ---
    [INFO] Changes detected - recompiling the module!
    [INFO] Compiling 1 source file to /Users/xxxx/IdeaProjects/JianzhiOffer/target/classes
    # process-test-resources阶段
    [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ jianzhioffer ---
    [INFO] skip non existing resourceDirectory /Users/xxxx/IdeaProjects/JianzhiOffer/src/test/resources
    # test-compile阶段
    [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ jianzhioffer ---
    [INFO] Changes detected - recompiling the module!
    [INFO] Compiling 1 source file to /Users/xxxx/IdeaProjects/JianzhiOffer/target/test-classes
    # test阶段
    [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ jianzhioffer ---
    [INFO] Surefire report directory: /Users/xxxx/IdeaProjects/JianzhiOffer/target/surefire-reports
    ...
    # package阶段
    [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ jianzhioffer ---
    [INFO] Building jar: /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT.jar
    # install阶段
    [INFO] --- maven-install-plugin:2.4:install (default-install) @ jianzhioffer ---
    [INFO] Installing /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT.jar to /Users/xxxx/repo/org/example/jianzhioffer/1.0-SNAPSHOT/jianzhioffer-1.0-SNAPSHOT.jar
    [INFO] Installing /Users/xxxx/IdeaProjects/JianzhiOffer/pom.xml to /Users/xxxx/repo/org/example/jianzhioffer/1.0-SNAPSHOT/jianzhioffer-1.0-SNAPSHOT.pom
    

3.5 查看插件信息

  • maven中的插件在编写时,一般都绑定了默认的生命周期阶段。例如,上面自定义verify阶段的插件目标时,其实去除<phase>标签,仍然可以看到maven-source-plugin:3.0.1:jar-no-fork的输出。

  • 可以通过如下命令查看插件的信息,包括插件中的所有插件目标、每个插件目标默认绑定的生命周期阶段等。

    # 命令
    mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:3.0.1 -Ddetail
    
  • 部分输出信息:

    # 输出的部分信息
    source:jar-no-fork
      Description: This goal bundles all the sources into a jar archive. This
        goal functions the same as the jar goal but does not fork the build and is
        suitable for attaching to the build lifecycle.
      Implementation: org.apache.maven.plugins.source.SourceJarNoForkMojo
      Language: java
      Bound to phase: package
    

3.6 自己对插件绑定的分析

基于jar-no-fork插件目标进行分析:

  1. 使用默认绑定:

    • jar-no-fork原本的默认绑定是package阶段,不指定<phase>标签,默认与package阶段绑定。
    • 执行mvn verify时,根据阶段之间的前后依赖关系,会先执行package阶段。因此,会有maven-source-plugin:3.0.1:jar-no-fork的输出。
  2. 指定生命周期阶段:

    • 如果明确指定<phase>标签,则将与verify阶段绑定。
    • 执行mvn verifyverify阶段时,会有maven-source-plugin:3.0.1:jar-no-fork的输出。
  3. 同一插件目标,绑定多个阶段: 按照阶段的先后顺序,多次执行目标插件

    • 绑定信息如下:

      <executions>
          <execution>
              <id>verify-bind</id>
              <phase>verify</phase>
              <goals>
                  <goal>jar-no-fork</goal>
              </goals>
          </execution>
          <execution>
              <id>package-bind</id>
              <phase>package</phase>
              <goals>
                  <goal>jar-no-fork</goal>
              </goals>
          </execution>
      </executions>
      
    • 执行输出如下:

      [INFO] --- maven-source-plugin:3.0.1:jar-no-fork (package-bind) @ jianzhioffer ---
      [INFO] Building jar: /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT-sources.jar
      [INFO] 
      [INFO] --- maven-source-plugin:3.0.1:jar-no-fork (verify-bind) @ jianzhioffer ---
      [INFO] Building jar: /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT-sources.jar
      
  4. 同一阶段,绑定多个插件目标: 按照插件定义的先后顺序进行执行

    • 绑定关系如下:

      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-shade-plugin</artifactId>
          <version>3.1.1</version>
          <executions>
              <execution>
                  <id>package-shade</id>
                  <phase>package</phase>
                  <goals>
                      <goal>shade</goal>
                  </goals>
                  ...
              </execution>
          </executions>
      </plugin>
      
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-source-plugin</artifactId>
          <version>3.0.1</version>
          <executions>
              <execution>
                  <id>package-source-jar</id>
                  <phase>package</phase>
                  <goals>
                      <goal>jar-no-fork</goal>
                  </goals>
              </execution>
          </executions>
      </plugin>
      
    • 输出信息如下:

      # 执行package阶段的默认绑定
      [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ jianzhioffer ---
      [INFO] Building jar: /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT.jar
      # 执行package阶段的自定义绑定:package-shade
      [INFO] --- maven-shade-plugin:3.1.1:shade (package-shade) @ jianzhioffer ---
      [INFO] Replacing original artifact with shaded artifact.
      [INFO] Replacing /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT.jar with /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT-shaded.jar
      # 执行package阶段的自定义绑定:package-source-jar
      [INFO] --- maven-source-plugin:3.0.1:jar-no-fork (package-source-jar) @ jianzhioffer ---
      [INFO] Building jar: /Users/xxxx/IdeaProjects/JianzhiOffer/target/jianzhioffer-1.0-SNAPSHOT-sources.jar
      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值