5 Maven生命周期和插件
命令行的输入往往就对应了声明周期,Maven的生命周期是抽象的,其实际行为都是由插件来完成。生命周期和插件两者协同工作,密不可分。
一、何为声明周期
Maven的生命周期就是为了对多有的构建过程进行抽象和统一。总结出了一套高度完善的、易扩展的生命周期。这个生命周期包含项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构件步骤。几乎所有项目的构建,都能映射到这样一个声明周期上。
Maven的生命周期是抽象的,这意味着生命周期本身不做任何实际的工作,在Maven的世界中,实际的任务都交给插件完成。
每一个构建步骤都可以绑定一个或者多个插件行为,而且Maven为大多数构建步骤编写并绑定了默认的插件。当 用户有特殊需求的时候,也可以配置插件定制构建行为,甚至自己编写插件。
二、生命周期详解
2.1 三套生命周期
分别为:clean、default和site。clean:清理项目;default:构建项目;site:建立项目站点。
每个生命周期包含一些阶段(phase),这些阶段是有顺序的,并且后面的阶段依赖于前面的阶段,用户和Maven最直接的交互方式就是调用这些生命周期阶段。例子:clean生命周期,有pre-clean,clean,post-clean。当调用pre-clean时,只执行pre-clean阶段。当调用clean的时候,执行pre-clean,和clean。如果调用post-clean,则执行pre-clean、clean、post-clean。
较之于生命周期阶段的前后依赖关系,三套生命周期本身是相互独立的。
2.2 clean生命周期
1)pre-clean:执行一些清理前需要完成的工作。
2)clean:清理上一次构件生成的文件。
3)post-clean:执行一些清理后需要完成的工作。
2.3 default生命周期
default生命周期定义了真正构建时需要执行的所有步骤,它是所有生命周期中最核心的部分,其中包含的阶段如下:
- validate
- initialize
- generate-sources
- process-sources:处理项目主资源文件,是对src/main/resources目录的内容进行变量替换工作后,复制到项目输出的主classpath目录中。
- generate-resources
- process-resources
- compile:编译项目的主源码,编译src/main/java目录下的Java文件至项目输出的主classpath目录中。
- process-classes
- generate-test-sources
- process-test-sources:处理项目测试资源文件。对src/test/resources目录的内容进行变量替换等工作之后,复制到项目输出的测试classpath目录中。
- generate-test-resources
- process-test-resources
- test-compile:编译项目的测试代码;编译src/test/java目录下的Java文件至项目输出的测试classpath目录中。
- process-test-classes
- test:使用单元测试框架运行测试,测试代码不会被打包或部署。
- prepare-package
- package:接受编译好的代码,打包成可发布的格式,如JAR。
- pre-integration-test
- integration-test
- post-integration-test
- verify
- install:将包安装到Maven本地仓库,供本地其他Maven项目使用。
- deploy:将最终的包复制到远程仓库,供其他开发人员和Maven项目使用。
2.4 site生命周期
目的:建立和发布站点信息,Maven能够基于POM所包含的信息,自动生成一个友好的站点,方便团队交流和发布项目信息。
阶段:
1)pre-site:执行一些在生成项目站点之前需要完成的工作
2)site:生成项目站点文档
3)site-deploy:将生成的项目站点发布到服务器上。
2.5 命令行与生命周期
1)$mvn clean:该命令调用clean生命周期的clean阶段。
2)$mvn test:该命令调用default生命周期的test节点。
3)$mvn clean install:该命令调用clean生命周期的clean阶段和default生命周期的install阶段。经常使用!
4)$mvn clean deploy site-deploy:执行三个生命周期的三个阶段。
三、插件目标:
Maven的核心仅仅定义了抽象的生命周期,具体的任务交由插件完成,插件以独立的构件形式存在。
一个插件有多个目标,每个功能就是一个插件目标,所以一个插件有多个功能。
四、插件绑定
Maven的生命周期与插件相互绑定,用以完成实际的构建任务。具体而言,是生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务。
4.1 内置绑定
为了能让用户几乎不用任何配置就能构建Maven项目,Maven在核心为一些主要的生命阶段绑定了多个插件的目标,当用户通过命令调用生命阶段的时候,对应的插件目标就会执行相应的任务。
4.2 自定义绑定
除了内置绑定以外,用户还能够自己选择将某个插件目标绑定到生命周期的某个阶段上。
例子:创建项目的源码jar包,maven-sources-plugin可以帮助我们完成任务,它的jar-no-fork目标能够将项目的主代码打包成jar文件,可以将其绑定到default生命周期的verify阶段上,在执行完成集成测试后和安装构件之前创建源码jar包。
插件的配置如下:
配置除了基本的插件坐标声明之外,还有插件执行配置。executions下每个execution子元素可以用来配置执行一个任务。
<id>:attach-sources任务
<phase>:绑定到verify声明周期阶段上。
<goals>:配置指定要执行的插件目标。
如果不添加phase元素配置生命周期阶段,插件目标也能绑定到生命周期中,原因:很多插件的目标在编写的时候已经定义了默认绑定阶段。使用maven-help-plugin查看插件详细信息,了解插件目标的默认绑定阶段。
例子: mvn help:describe-Dplugin =groupId:artifactId:version -Ddetail
查看 Bound to phase 查看绑定到那个阶段。
如果多个目标绑定到同一个阶段,它的执行顺序按照声明顺序执行。
五、插件配置
完成插件和生命周期的绑定之后,用户还可以配置插件目标的参数,进一步调整插件目标所执行的任务。可以通过命令行和POM配置方式配置这些参数。
5.1 命令行插件配置
用户可以在Maven命令中使用-D参数,并伴随一个参数键=参数值的形式,来配置插件目标的参数。
例子:maven-surefire-plugin提供了一个maven.test.skip参数,当其值为true的时候,就会跳过执行测试。则执行命令如下:
$mvn install -D maven.test.skip=true
参数-D是Java自带的,其功能是通过命令行设置一个Java系统属性,Maven简单的重用了该参数,在准备插件的时候检查系统属性,便实现了插件参数的配置。
5.2 pom中插件全局配置
有些参数的值从项目创建到项目发布都不会变化,则在POM文件中一次性配置就显然比重复在命令行输入要方便。
用户可以在声明插件的时候,对插件进行一个全局配置,所有该基于该插件目标的任务,就会使用这些配置。
例子:配置maven-compiler-plugin编译Java1.8版本的源文件,生成jvm1.8兼容的字节码文件。
5.3 POM中插件任务配置
可以为某个插件任务配置特定的参数。
例子:maven-antrun-plugin,有一个目标run,可以用来Maven中调用Ant任务。将maven-antrun-plugin:run绑定到多个生命阶段,再加以不同的配置,就可以让Maven在不同的生命阶段执行不同的任务。
maven-antrun-plugin:run与validate阶段绑定从而构成一个id为ant-validate的任务。
插件全局配置中的configuration元素位于plugin元素下面,而这里测configuration元素则位于execution元素下,表示这是特定任务的配置,而非插件整体的配置。
六、获取插件信息
1.从官方网站获取
2.使用maven-help-plugin描述插件
mvn help :describe -D plug=groupId:artifactId:version
七、从命令行调用插件
mvn -h 查看mvn命令帮助。
options:可用选项,mvn命令有20多个选项。
goals:插件目标。
phases:生命周期阶段。
可以通过mvn命令激活生命周期阶段,从而执行那些绑定在生命周期阶段上的插件目标。Maven还支持直接从命令行调用插件目标。原因:某些任务不适合绑定在生命周期上,例如:描述插件——maven-help-plugin:describe。
使用例子:
mvn groupId:artifactId:version:goal -Dplugin=compile。
八、插件解析机制
为了方便用户使用和配置插件,Maven不需要用户提供完整的插件坐标信息,就可以解析到正确的插件。
本节介绍Maven的运行机制。
8.1 插件仓库
与依赖构件一样,先从本地仓库查找插件,如果不存在则下载。
但是,Maven会区别对依赖的远程仓库和插件的远程仓库。之前介绍的配置远程仓库,只对一般依赖有效果。
例子:
除了pluginRepositories和pluginRepository之外,其他与之前讲述的构件依赖一直。关闭了snapshot的支持,防止出问题。
这个可以放在pom中或者settings.xml中。
8.2 插件的默认groupId
在pom中配置插件的时候,如果插件是Maven官方插件,groupId可以不用写,会自动默认org.apache.maven.plugins补齐。但是不推荐这样,防止对不熟悉Maven的成员产生疑惑。
8.3 解析插件版本
版本也可以不指定,如果不指定,首先Maven在超级POM中为所有核心插件设定了版本,如果不指定版本,则版本就已经确定了。
如果插件不属于核心插件。则Maven就会检查所有仓库中可用版本,然后做出选择,也是通过groupId/artifactId/maven-metadata.xml选择。不在阐述。
这也是不推荐的做法,原因你懂得!
8.4 解析插件前缀
插件前缀与groupId:artifactId是一一对应,这种匹配关系存储在仓库元数据中(这次不同是groupId/maven-metadata.xml)。
Maven在解析插件仓库元数据的时候,会使用默认的groupId。可以使用settings.xml配置仓库元数据
例子:当解析到dependency:tree
首先默认groupId归并所有插件仓库的元数据;然后找到对应的元数据,找到对应的artifactId为maven-dependency-plugin;结合groupId找到version,就找到了完整的坐标了!