Maven实战.插件

插件目标

在进一步详述插件和生命周期的绑定关系之前,必须先了解插件目标(PluginCoal)的概念。我们知道,Maven 的核心仅仅定义了抽象的生命周期具体的任务是交由插件完成的,插件以独立的构件形式存在,因此,Maven 核心的分发包只有不到3MB的大小,Maven 会在需要的时候下载并使用插件。

对于插件本身,为了能够复用代码,它往往能够完成多个任务。例如maven-dependency-plugin,它能够基于项目依赖做很多事情。它能够分析项目依赖,帮助找出潜在的无用依赖;它能够列出项目的依赖树,帮助分析依赖来源;它能够列出项目所有已解析的依赖等等。为每个这样的功能编写一个独立的插件显然是不可取的,因为这些任务背后有很多可以复用的代码,因此,这些功能聚集在一个插件里,每个功能就是一个插件目标。

maven-dependency-plugin 有十多个目标,每个目标对应了一个功能,上述提到的几个功能分别对应的插件目标为dependency : analyze、dependency : tree 和 dependency : list。这是一种通用的写法,冒号前面是插件前缀,冒号后面是该插件的目标。类似地,还可以写出compiler : compile(这是 maven-compiler-plugin 的 compile 目标)和surefire : test(这是 maven-sure-fire-plugin 的 test 目标)。

插件绑定

Maven 的生命周期与插件相互绑定,用以完成实际的构建任务。具体而言,是生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务。例如项目编译这一任务,它对应了 default 生命周期的 compile 这一阶段,而 maven-compiler-plugin 这一插件的 compile 目标能够完成该任务。因此,将它们绑定,就能实现项目编译的目的,如下
在这里插入图片描述

内置绑定

为了能让用户几乎不用任何配置就能构建 Maven 项目,Maven 在核心为一些主要的生命周期阶段绑定了很多插件的目标,当用户通过命令行调用生命周期阶段的时候,对应的插件目标就会执行相应的任务。

clean 生命周期仅有 pre-clean、clean 和 post-clean 三个阶段,其中的clean 与 maven-clean-plugin : clean 绑定。maven-clean-plugin 仅有clean 这一个目标,其作用就是删除项目的输出目录。clean 生命周期阶段与插件目标的绑定关系如下图所示。
在这里插入图片描述

site 生命周期有 pre-site、site、post-site 和 site-deploy 四个阶段,其中,site 和 maven-siteplugin : site 相互绑定,site-deploy 和 maven-site-plugin : depoy相互绑定。maven-site-plugin 有很多目标,其中,site 目标用来生成项目站点,deploy 目标用来将项目站点部署到远程服务器上。site 生命周期阶段与插件目标的绑定关系如下图所示。
在这里插入图片描述
相对于 clean 和 site 生命周期来说,default 生命周期与插件目标的绑定关系就显得复杂一些。这是因为对于任何项目来说,例如 jar 项目和 war 项目,它们的项目清理和站点生成任务是一样的,不过构建过程会有区别。例如 jar 项目需要打成 JAR 包,而 war 项目需要打成 WAR 包。

由于项目的打包类型会影响构建的具体过程,因此,defaut 生命周期的阶段与插件目标的绑定关系由项目打包类型所决定,打包类型是通过 POM 中的 packaging 元素定义的。最常见、最重要的打包类型是 jar,它也是默认的打包类型。基于该打包类型的项目,其 default 生命周期的内置插件绑定关系及具体任务如下图所示。
在这里插入图片描述
注意,上图只列出了拥有插件绑定关系的阶段,default 生命周期还有很多其他阶段,默认它们没有绑定任何插件,因此也没有任何实际行为。

除了默认的打包类型 jar 之外,常见的打包类型还有 war、pom、maven-plugin、ear 等。它们的 defaut 生命周期与插件目标的绑定关系可参阅 Maven 官方文档,这里不再赘述。

你也可以从 Maven 项目的命令行执行 mvn clean install 命令,看到项目在构建过程中执行了哪些插件目标。

自定义绑定

除了内置绑定以外,用户还能够自己选择将某个插件目标绑定到生命周期的某个阶段上,这种自定义绑定方式能让 Maven 项目在构建过程中执行更多更富特色的任务。

一个常见的例子是创建项目的源码 jar 包,内置的插件绑定关系中并没有涉及这一任务,因此需要用户自行配置。maven-source-plugin 可以帮助我们完成该任务,它的 jar-no-fork 目标能够将项目的主代码打包成iar 文件,可以将其绑定到 default 生命周期的 verify 阶段上、在执行完集成测试后和安装构件之前创建源码 jar 包。具体配置见如下代码:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>2.2.1</version>
    <executions>
        <execution>
            <id>attach-sources</id>
            <phase>verify</phase>
            <goals>
                <goal>jar-no-fork</goal>
            </goals>
        </execution>
    </executions>
</plugin>

在 POM 的 build 元素下的 plugins 子元素中声明插件的使用,该例中用到的是 maven-scurce-plugin,其 groupId 为org:apache.maven.plugins,这也是 Maven 官方插件的 groupId,紧接着 artifactld 为 maven-source-plugin,version 为 2.2.1。对于自定义绑定的插件,用户总是应该声明一个非快照版本,这样可以避免由于插件版本变化造成的构建不稳定性。

上述配置中,除了基本的插件坐标声明外,还有插件执行配置,executions 下每个 execution 子元素可以用来配置执行一个任务。该例中配置了一个 id 为 attach-sources 的任务通过 phase 配置,将其绑定到 verify 生命周期阶段上,再通过 goals 配置指定要执行的插件目标。至此,自定义插件绑定完成。运行 mvn verify 就能看到如下输出:

[INFO] --- source:2.2.1:jar-no-fork (attach-sources) @ hello-world ---
[INFO] Building jar: D:\Work\gittest\demo-maven-practical\hello-world\target\hello-world-1.0-SNAPSHOT-sources.jar

我们可以看到,当执行 verify 生命周期阶段的时候,maven-source-plugin:jar-no-fork 会得以执行,它会创建一个以“ -sources.jar”结尾的源码文件包。

有时候,即使不通过 phase 元素配置生命周期阶段,插件目标也能够绑定到生命周期中去。例如,可以尝试删除上述配置中的 phase 一行,再次执行mvn verify,仍然可以看到 maven-source-plugin:jar-no-fork 得以执行。出现这种现象的原因是:有很多插件的目标在编写时已经定义了默认绑定阶段。可以使用 maven-help-plugin 查看插件详细信息,了解插件目标的默认绑定阶段。运行命令如下:

mvn help:describe -Dplugin=org.apache.maven.plugins:maven-source-plugin:3.2.1 -Ddetail

该命令输出对应插件的详细信息。在输出信息中,能够看到关于目标 jar-no-fork 的如下信息:

...
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.plugin.source.SourceJarNoForkMojo
  Language: java
  Bound to phase: package

  Available parameters:
...

该输出包含了一段关于 jar-no-fork 目标的描述,这里关心的是 Bound to phase 这一项,它表示该目标默认绑定的生命周期阶段(这里是package)。也就是说,当用户配置使用 maven-source-plugin 的 jar-no-fork 目标的时候,如果不指定 phase 参数,该目标就会被绑定到 package Maven 生命周期 default周期 的 package 阶段。

当插件目标被绑定到不同的生命周期阶段的时候,其执行顺序会由生命周期阶段的先后顺序决定。如果多个目标被绑定到同一个阶段,它们的执行顺序会是怎样?答案很简单,当多个插件目标绑定到同一个阶段的时候,这些插件声明的先后顺序决定了目标的执行顺序。

插件配置

完成了插件和生命周期的绑定之后,用户还可以配置插件目标的参数,进一步调整插件目标所执行的任务,以满足项目的需求。几乎所有 Maven 插件的目标都有一些可配置的参数,用户可以通过命令行和 POM 配置等方式来配置这些参数。

命令行插件配置

在日常的 Maven 使用中,我们会经常从命令行输入并执行 Maven 命令。在这种情况下如果能够方便地更改某些插件的行为,无疑会十分方便。很多插件目标的参数都支持从命令行配置,用户可以在 Maven 命令中使用 -D 参数,并伴随一个参数键=参数值的形式,来配置插件目标的参数。

例如,maven-surefire-plugin 提供了一个 maven.test.skip 参数,当其值为 true 的时候,就会跳过执行测试。于是,在运行命令的时候,加上如下 -D 参数就能跳过测试:

 mvn install -Dmaven.test.skip=true

参数- D 是 Java 自带的,其功能是通过命令行设置一个 Java 系统属性,Maven 简单地重用了该参数,在准备插件的时候检查系统属性,便实现了插件参数的配置。

POM中插件全局配置

并不是所有的插件参数都适合从命令行配置,有些参数的值从项目创建到项目发布都不会改变,或者说很少改变,对于这种情况,在 POM 文件中一次性配置就显然比重复在命令行输入要方便。

用户可以在声明插件的时候,对此插件进行一个全局的配置。也就是说,所有该基于该插件目标的任务,都会使用这些配置。例如,我们通常会需要配置 maven-compiler-plugin 告诉它编译 Java 1.5 版本的源文件,生成与 JVM1.5 兼容的字节码文件,见代码如下:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <source>1.5</source>
        <target>1.5</target>
    </configuration>
</plugin>

这样,不管绑定到 compile 阶段的 maven-compiler-plugin:compie 任务,还是绑定到 test-compiler 阶段的 maven-compiler-plugin:testCompiler 任务,就都能够使用该配置,基于Java1.5 版本进行编译。

插件全局配置元素是 configuration 元素。

POM中插件任务配置

除了为插件配置全局的参数,用户还可以为某个插件任务配置特定的参数。以 maven-antrumn-plugin 为例,它有一个目标 run,可以用来在 Maven 中调用 Ant 任务。用户将 maven-antrun-plugin:run 绑定到多个生命周期阶段上,再加以不同的配置,就可以让 Maven 在不同的生命阶段执行不同的任务,如下:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.8</version>
    <executions>
        <execution>
            <id>ant-validate</id>
            <phase>validate</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <tasks>
                    <echo>i am bound to validate phase</echo>
                </tasks>
            </configuration>
        </execution>
        <execution>
            <id>ant-verify</id>
            <phase>verify</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <tasks>
                    <echo>i am bound to verify phase</echo>
                </tasks>
            </configuration>
        </execution>
    </executions>
</plugin>

在上述代码片段中,首先,maven-antrun-plugin:run 与 validate 阶段绑定,从而构成一个 id 为 ant-validate 的任务。插件全局配置中的 configuration 元素位于 plugin 元素下面,而这里的 confguration 元素则位于 execution 元素下,表示这是特定任务的配置,而非插件整体的配置。这个 ant-validate 任务配置了一个echo Ant 任务,向命令行输出一段文字,表示该任务是绑定到 validate 阶段的。第二个任务的 id 为 ant-verify,它绑定到了 verify 阶段,同样它也输出一段文字到命令行,告诉该任务绑定到了verify 阶段。

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值