一、插件目标
Maven的核心仅定义了抽象的生命周期,具体的任务是交由插件完成,插件以独立的构件形式存在。
对于插件本身,为了代码复用,它往往具备多个功能,而每个功能都统称为插件目标(Plugin Goal)。
如:maven-dependency-plugin,基于项目依赖做很多事情。
1 帮助分析项目依赖,帮助找出潜在的无用依赖;
2 列出项目依赖树,帮助分析依赖来源
3 列出项目已解析的依赖 等...
这些任务有很多代码可以复用。因此,这些功能聚集在一个插件中,每个功能就是一个插件目标。
插件目标使用语法:
1 完整命令 mvn groupId:artifactId:version:goal 如 mvn org.apache.maven.plugins:maven-dependency-plugin:3.0.2:tree
2 简化version mvn groupId:artifactId:goal 如 mvn org.apache.maven.plugins:maven-dependency-plugin:tree
3 使用插件前缀 mvn 插件前缀:goal 如 mvn dependency:tree
二、插件绑定
Maven的生命周期与插件目标相互绑定,用以完成实际的构建任务。
三、内置绑定
为了使用户几乎不用任何配置就能构建Maven项目,Maven在核心为一些主要的生命周期阶段绑定了很多插件的目标,
当用户通过命令行调用生命周期时,对应的插件目标就会执行相应的任务。
如下图(default生命周期的阶段与插件目标的绑定关系由项目打包类型决定(packaging元素)下图以jar包构建为例)
生命周期 | 阶段(phase) | 内置插件 | 执行任务 |
---|---|---|---|
clean | pre-clean | ||
clean | maven-clean-plugin:clean | 删除项目的输出目录 | |
post-clean | |||
default | vaildate | ||
intianlize | |||
generate-sources | |||
proccess-sources | |||
generate-resoureces | |||
process-resources | maven-resources-plugin:resources | 复制主资源文件至主输出目录 | |
compile | maven-compiler-plugin:compile | 编译主代码至主输出目录 | |
process-classes | |||
generate-test-sources | |||
process-test-sources | |||
generate-test-resources | |||
process-test-resources | maven-resources-plugin:testResources | 复制测试资源文件至测试输出目录 | |
test-compile | maven-compiler-plugin:testCompile | 编译测试代码至测试输出目录 | |
process-test-classes | |||
test | maven-surefire-plugin:test | 执行测试用例 | |
prepare-package | |||
package | maven-jar-plugin:jar | 创建项目jar包 | |
pre-integration-test | |||
integration-test | |||
post-integration-test | |||
verify | |||
install | maven-install-plugin:install | 将项目输出构件安装到本地仓库 | |
deploy | maven-deploy-plugin:deploy | 将项目输出构件安装到远程仓库 | |
site | pre-site | ||
site | maven-site-plugin:site | 生成项目站点 | |
peo-site | |||
site-deploy | maven-site-plugin:deploy | 将项目站点部署到远程服务器上 |
Ps:空白的生命周期阶段,默认没有绑定任何插件,因此也没有任何实际行为
除默认打包类型jar外,常见的打包类型还有war、pom、maven-plugin、ear等。查看相关类型插件绑定官网http://maven.apache.org/guide...
四、自定义绑定
除了内置绑定以外,用户可以选择将某个插件目标绑定到生命周期的某个阶段,能让Maven项目在构建过程中执行更多更富特色的任务。
如maven-source-plugin:jar-no-fork,能够将项目主代码打成jar文件。将其绑定到default生命周期的verify阶段上,在执行完继承测试后和安装构件之前创建源码jar包。配置如下
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions> <!-- 插件执行配置 -->
<execution> <!-- executions下每个execution子元素可以配置执行一个任务 -->
<id>attach-sources</id> <!-- 配置任务id -->
<!-- <phase>verify</phase> --> <!-- phase元素配置绑定生命周期阶段 -->
<goals> <!-- 配置要执行的插件目标 -->
<goal>jar-no-fork</goal>
</goals>
<execution>
</executions>
</plugin>
</plugins>
</build>
完成自定义插件绑定后,运行mvn verify即可。
在上述代码中,注释了phase元素也能实现绑定,原因是很多插件目标在编写时已经定义了默认绑定阶段,可以使用maven-help-plugin查看插件详细信息,了解插件目标的默认绑定阶段。
mvn help:describe -Dplugin=groupId:artifactId:version
当插件目标绑定到不同的生命周期时,其执行顺序会由生命周期阶段的先后顺序决定。如果多个目标被绑定到同一个阶段,这些插件声明的先后顺序决定目标的执行顺序。
五、插件配置
完成插件目标与生命周期绑定后,用户还可以配置插件目标的参数,进一步调整插件目标所执行的任务,以满足项目的需求。几乎所有Maven插件目标都有一些可配置参数,可通过命令行和POM配置等方式来配置参数。
1)命令行插件配置
使用-D参数,并伴随一个参数名=参数值的形式,来配置参数
(命令行参数是由插件参数的表达式(Expression)决定,并非所有插件目标参数都有表达式,只能在POM中配置)
如maven-surrfire-plugin插件提供了一个maven.test.skip参数,当其值为true时,就会跳过执行测试。
mvn install -Dmaven.test.skip=true
2)POM中插件全局配置
并非所有插件参数都适合从命令行配置,有些参数的值从项目构建到项目发布都不会改变,或很少改变,在POM文件中一次性配置显然比重复在命令行输入要方便。
如mvan-compiler-plugin 可以配置全局参数 实现compile以及testCompile任务都能使用全局配置。
<build>
<plugins>
<plugin>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<configuration> <!-- 声明插件全局配置 所有基于该插件目标的任务,都会使用这些配置 -->
...
</configuration>
</plugin>
</plugins>
</builds>
3)POM中插件任务配置
除了为插件配置全局的参数,还可以为某个插件任务配置特定的参数。
如maven-antrun-plugin 可以配置插件任务参数,使run目标任务在不同生命周期输出不同的语句。
<build>
<plugins>
<plugin>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<executions>
<execution>
<id>...</id>
<phase>...</phase>
<goals>
<goal>...</goal>
</goals>
<configuration> <!-- 插件任务一配置 -->
...
</configuration>
</execution>
<execution>
<id>...</id>
<phase>...</phase>
<goals>
<goal>...</goal>
</goals>
<configuration> <!-- 插件任务二配置 -->
...
</configuration>
</execution>
...
</executions>
</plugin>
</plugins>
</builds>
六、获取插件信息
仅仅理解如何配置使用插件是不够的,实现一个构建任务,用户需知道去哪找到合适的插件,并详细了解该插件的配置点。由于Maven的插件非常多,而且这其中大部分没有完善的文档,因此使用正确的插件并进行正确的配置,不容易。
1)在线插件信息
基本上所有的Maven插件都来自于apache和Codehaus。
apache | 说明 | 官方插件,用户多,稳定性好 |
详细列表 | http://maven.apache.org/plugi... | |
下载地址 | http://repo1.maven.org/maven2... | |
Codehaus | 说明 | 文档和可靠性相对较差,遇到问题,往往需要自己看源码 |
详细列表 | http://mojo.codehaus.org/plug... | |
下载地址 | http://repository.codehaus.or... |
虽然并非所有插件都提供了完善的文档,但一些核心插件的文档还是非常丰富的。
一般来说,通过阅读插件在文档中的使用介绍和实例,就应该能够在自己的项目中很好地使用该插件。
当我们需要了解非常细节的目标参数时,就需要进一步访问该插件每个目标的文档。文档详细解释了该参数的作用、类型等信息。
2)使用maven-help-plugin插件
除了访问在线的插件文档之外,还可以借助maven-help-plugin来获取插件的详细信息。
执行maven-help-plugin的describe目标,指定要查询的插件的坐标,可查询插件的坐标,前缀(Goal Prefix),目标信息
mvn help:describe -Dplugin = (groupId:artifactId[:version] | Goal Prefix) -Dgoal = goal -Ddetail
七、从命令行调用插件
mvn -h 显示mvn命令帮助,可以看到如下信息:
usage:mvn [options] [<goal(s)]>] [<phase(s)>]
Options:
...
options表示可用的选项,除了选项之外,mvn命令后面可以添加一个到多个goal和phase,分别指插件目标和生命周期阶段。mvn命令可以激活生命周期阶段,从而执行那些绑定在生命周期阶段上的插件目标。也可以直接执行插件目标,因为有些插件目标不适用于生命周期阶段,如maven-help-plugin:describe。
直接执行插件目标语法 在上文中已提及,可在插件目标中查看。
八、插件解析机制
在命令行中执行插件目标,可使用插件前缀替代坐标,方便用户使用和配置插件。
Maven的这一特性是双刃剑,虽然它简化了插件的使用和配置,但如果出现问题,用户很难定位出问题的插件构件。
如mvn help:system 执行了什么插件。它的坐标是什么。这与Maven的插件解析机制有关。
1)插件仓库
与依赖构件一样,插件构件同样基于坐标存储在Maven仓库中,在需要的时候,Maven会先从本地仓库寻找插件,不存在则从远程仓库找到插件,下载到本地仓库使用。
插件的远程仓库不同于依赖的远程仓库,配置方式也不同,插件仓库配置如下:
<pluginRepositories>
<pluginRepository>
... <!-- 此处与依赖远程仓库配置一样,可参考阅读总结二查看 -->
</pluginRepository>
...
</pluginRepositoties>
Maven内置了插件仓库指向中央仓库,并关闭了对SNAPSHOT的支持。
一般来说,中央仓库所包含的插件完全能够满足我们的需要,因此也不需要配置其他的插件仓库,只有在很少的情况下,项目使用的插件无法在中央仓库找到,或者自己编写了插件,可以参考上述配置,在POM中或settings.xml中 加入其他插件仓库。
2)插件的默认groupId
在POM中配置插件时,如果该插件是Maven官方插件(groupId为org.apache.maven.plugins),则可以省略groupId配置。
不推荐使用这一特性,只省略一行配置,但会让团队中不熟悉Maven的成员感到费解。
3)解析插件版本
同样为了简化插件的配置和使用,用户可没有提供插件的版本,Maven会自动解析插件版本。
首先,Maven在超级POM中为所有核心插件设定了版本,超级POM是所有Maven项目的父POM,所有项目都继承了这个超级POM配置。所以用户使用插件未设定插件版本的情况有以下几种:
1 核心插件:通过超级POM继承设定版本
2 非核心插件:通过仓库元数据 groupId/artifactId/maven-metadata.xml ,遍历并归并本地仓库和远程仓库的仓库元数据,根据latest和release计算出插件的版本。Maven3之后使用release,避免使用latest获取到快照版本,因为快照版本的频繁更新会导致插件行为的不稳定。
4)解析插件前缀
mvn命令行支持使用插件前缀来简化插件的调用。Maven是如何通过插件前缀获取插件的坐标的?
插件前缀与groupId:artifactId是一一对应的,这种匹配关系存储在仓库元数据中,该仓库员数据位于groupId/maven-metadate.xml,Maven在解析插件仓库元数据时,会默认使用org.apache.maven.plugins和org.codehaus.mojo两个groupId,可以再settings.xml中配置其他groupId
<settings>
...
<pluginGroups>
<pluginGroup>...</pluginGroup>
</pluginGroups>
...
<settings>
插件仓库元数据中存储了所有插件前缀与group:artifactId的对应关系
插件仓库元数据检查顺序为:apache -> codehaus -> 用户自定义插件组 -> 都不包含该前缀,则报错