五、生命周期与插件
1、Maven有三套独立的生命周期:clean、default和site。 clean生命周期的目的是清理项目,default生命周期的目的是构建项目,site生命周期的目的是建立项目站点。
clean生命周期:pre-clean、clean、post-clean
default生命周期:validate、initialize、generate-sources、process-sources(处理项目主资源文件,对src/main/rescources目录内容进行变量替换等工作后,复制到项目输出的主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目录中)、test、
prepare-package、package(接受编译好的代码,打包成可发布的格式)、pre-integration-test、integration-test、post-integration-test、verify、install(将包安装到maven
本地仓库,供其他人和项目使用)、deploy(将最终的包复制到远程仓库,供其他开发人员和项目使用)
site生命周期:pre-site、site(生成项目站点文档)、post-site、site-deploy(将生成的站点发布到服务器上)。
2、命令行与生命周期
从命令行执行maven任务的最主要方式就是调用maven的生命周期阶段。
mvn clean 调用clean生命周期的clean阶段。
mvn test 调用default生命周期的test阶段。
mvn clean install 调用clean生命周期的clean阶段和defaulte生命周期的install阶段。
mvn clean deploy site-deploy 调用clean的阶段、default生命周期的deploy阶段,以及site生命周期的site-deploy阶段。
maven中主要的生命周期阶段并不多,而常用的maven命令实际是基于这些阶段简单组合而成的。
3、插件目标
maven的核心仅仅定义了抽象的生命周期,具体的任务是交由插件完成的,插件以独立的构件形式存在。
maven的生命周期与插件相互绑定,用以完成实际的构建任务。具体讲是生命周期的阶段与插件的目标相互绑定,以完成某个具体构建任务。
为了能让用户几乎不用任何配置就能构建maven项目,maven在核心为一些主要的生命周期阶段绑定了很多插件目标,当用户通过命令调用生命周期阶段的时候,对应的插件
目标就会执行相应的任务。
clean生命周期的pre-clean、clean和post-clean三个阶段,只有clean与maven-clean-plugin:clean绑定。maven-clean-plugin仅有clean这一个目标,其作用是删除项目输出目录。
site生命周期的pre-site、site、post-site和site-deploy四个阶段,其中,site和maven-site-plugin:site相互绑定,maven-site-plugin有很多目标,其中site目标用来生成项目站点,
deploy目标用来将项目站点部署到远程服务器上。
default生命周期与插件目标的绑定关系就显得复杂些。这是因为对于任何项目来说,例如jar项目和war项目,他们的项目清理和站点生成是一样的,不过构建过程会有区别。
例如jar项目需要打包成JAR包,而war项目需要打成WAR包。由于项目的打包类型会影响构建的具体过程,因此,default生命周期的阶段与插件目标的绑定关系由项目打
包类型所决定,打包类型是通过POM中的packaging元素定义的。基于打包类型是jar的项目,其default生命周期内置插件绑定关系及具体任务如表:
default生命周期还有很多其他阶段,默认他们没有绑定任何插件,因此也没有任何实际行为。
4、自定义绑定
除了内置绑定以外,用户还能够自己选择某个插件目标绑定到生命周期的某个阶段上,这种自定义绑定方式能让maven项目在构建过程中执行更多更富特色的任务。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution>
<id>attched-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
在POM的build元素下的plugins子元素中声明插件的使用,该例中用到的是maven-source-plugin,其中groupId为org.apahe.maven.plugins,这是maven官方插件的groupId。
对于自定义绑定的插件,用户总是应该声明一个非快照版本,这样可以避免由于插件版本变化造成的构建不稳定性。除了基本插件坐标声明外,还有插件执行配置,
executions下每个execution子元素可以用来配置执行一个任务。该例中配置一个id为attch-sources的任务,通过phase配置,将其绑定到verify生命周期阶段上,再通过goals
配置指定要执行的插件目标。
有时候,即使不通过phase元素配置声明周期阶段,插件目标也能够绑定到生命周期中去。原因是,很多插件的目标在编写时已经定义了默认绑定阶段。
可以使用maven-help-plugin 查看插件详细信息,了解插件目标的默认绑定阶段。
5、插件配置
完成了插件和生命周期的绑定之后,用户还可以配置插件目标的参数,进一步调整插件目标所执行的任务,以满足项目的需求。
命令行配置:
在日常maven使用中,我们经常从命令行输入并执行maven命令。这种情况下,能够方便地改变某些插件的行为十分方便。 用户可以在maven命令中使用-D参数,
并伴随一个参数健=参数值的形式,来配置插件目标的参数。
$ mvn install-Dmaven.test.skip=true,参数-D是java自带的,其功能是通过命令行设置一个java系统属性,maven简单第重用了该参数,在准备插件的时候检查系统属性,
便实现了插件参数的配置。
全局配置:
并不是所有的插件参数都适合从命令行配置,有些参数的值从项目创建到项目发布都不会改变,或者说很少改变,对于这种情况,POM文件中一次性配置就显然比重复在
命令行输入要方便。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.1</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
这样,不管绑定到compile阶段的maven-compiler-plugin:compile任务,还是绑定到test-compiler阶段的maven-compiler-plugin:testCompiler任务,就能够使用该配置,
基于java1.5版本进行编译。
POM中插件任务配置:
除了为插件配置全局参数,用户还可以为某个插件任务配置特定参数,以maven-antrun-plugin,他有一个目标run,可以用来在maven中调用Ant任务。
用户将maven-antrun-plugin:run绑定到多个生命周期阶段上,再加以不同的配置,就可以让maven在不同的生命阶段执行不同的任务。
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</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>
</plugins>
</build>
上述代码片段中,首先maven-antrun-plugin:run与validate阶段绑定,从而构成一个id为ant-validate的任务。插件全局配置中的configuration元素位于plugin元素下面,
而这里的configuration元素则位于execution元素下,表示这是特定任务的配置,而非插件整体的配置。这个ant-validate任务配置了一个echo ant任务,
向命令行输出一段文字,表示该任务是绑定到validate阶段的。第二 个任务的id为ant-verify,它绑定到了verify阶段,同样她输出一段文字到命令行,
告诉该任务绑定到了verify阶段。
获取插件信息:
插件信息:基本上所有主要的maven插件都来自apache和Codeaus。
maven-help-plugin描述插件:除了访问在线的插件文档之外,还可以借助maven-help-plugin来获取插件信息。
从命令行调用插件
如果在命令行运行mvn-h来显示mvn命令帮助,就可以看到如下信息
usage:mvn [optiona] [<goal(s)>] [phase(s)]
options:
...
该信息高速我们mvn命令基本用法,options表示可用的选项,mvn命令有20多个选项,这里暂不详述。命令后面可以添加一个或者多个goal和phase,
他们分别指插件目标和生命周期阶段。可以通过mvn命令激活生命周期阶段,从而执行那些绑定在生命周期阶段上的插件目标。但maven还支持直接从命令行调用插件目标。
支持这种方式是因为有些任务不适合绑定生命周期上。
6、插件解析机制
为了方便用户使用和配置插件,Maven不需要用户提供完整的插件坐标信息,就可以解析到正确的插件,这样虽然简化了插件的使用和配置,可一旦插件的行为出现异常,
用户就很难快速定位到问题的插件构件。例如mvn help : system这样一条命令,到底执行了什么插件,该插件的groupId、artifactId和version分别是什么?
插件仓库:与依赖构件一样,插件构件同样基于坐标存储在maven仓库中。在需要的时候,maven会从本地仓库寻找插件,如果不存在,则从远程仓库查找。找到插件之后,
再下载到本地仓库使用。mave会区别对待依赖的远程仓库与插件仓库。当maven需要的依赖在本地仓库不存在时,它会去所配置的远程仓库查找,可是当maven需要的插件
在本地仓库不存在时,它就不会去这些远程仓库查找。插件的远程仓库使用pluginRepositories和pluginRepository配置。内置的插件远程仓库配置 如下。
这个默认插件仓库的地址就是*仓库.
项目使用的插件无法在*仓库找到,或者自己编写了插件,这个时候可以参考以上的配置,在POM或者settings.xml中加入其它的插件仓库配置。
插件的默认groupId:在POM中配置插件的时候,如果该插件是maven的官方插件,可以省略groupId配置。
解析插件版本:同样是为了简化插件配置和使用,在用户没有提供插件版本的情况下,maven会自动解析插件版本。maven在超级pom中为所有核心插件设定了版本,
超级pom是所有maven项目的父pom。所有项目都继承这个超级pom的配置,因此即使用户不加任何配置,maven使用核心插件的时候,他们的版本都就已经确定了,
这些插件包括maven-clean-plugin、maven-compiler-plugin、maven-surefire-plugin等。
如果用户使用某个插件时没有设定版本,而这个插件不属于核心插件的范畴,maven就会去检查所有仓库中可用的版本,然后做出选择。
以maven-compiler-plugin为例,在*仓库的仓库元数据为http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/maven-metadata.xml
内容如下:
maven遍历本地仓库和所有远程插件仓库,将该路径下的仓库元数据归并后,就能计算出latest和release的值。latest表示所有仓库中该构建的最新版本,而release表示最新的非快照版本。
解析插件前缀:mvn命令行支持使用插件前缀来简化插件调用,现在解释maven如何根据插件前缀解析到插件的坐标。插件前缀与groupId:artifactId是一一对应的,
这种匹配关系存在仓库元数据中,仓库元数据为groupId/maven-metadata.xml。maven解析插件仓库元数据的时候,会默认使用org.apache.maven.plugins和
org.codehaus.mojo两个groupId.可以通过配置settings.xml让maven检查其他groupId是哪个的插件仓库元数据:
基于该配置,maven就不仅仅会检查org/apache/maven/plugins/maven-metadata.xml和org/codehaus/mojo/maven-metadata.xml还会检查com/your/plugins/maven-metadata.xml
上述内容是从*仓库的org.apache.maven.plugins groupId下插件仓库元数据中截取的一些片段,从这段数据中就能看到maven-clean-plugin的前缀为clean,maven-compiler-plugin的
前缀为compiler,maven-dependency-plugin的前缀为dependency.
当maven解析到denpendency:tree这样的命令后,他首先基于默认的groupId归并所有插件仓库的元数据org/apache/maven/plugins/maven-metadata.xml.其次检查归并后的元数据,
找到对应的artifactId为maven-dependency-plugin,然后结合当前元数据的groupId找到对应的artifactId为maven-dependency-plugin然后结合当前元数据的groupI org.apache.maven.plugins.
解析到version,这是就得到了完整的插件坐标。