一. 何为生命周期
Maven 的生命周期就是为了对所有的构建过程进行抽象和统一。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤。 Maven 的生命周期是抽象的,不做任何实际工作,实际任务都交由插件完成。(这种思想与 template method 非常类似)每个构建步骤可以绑定一个或者多个插件行为。 Maven 为大多数构建步骤编写并绑定了默认插件,如: maven-compiler-plugin 和 maven-surefire-plugin 。
二. 生命周期详解
1. 三套生命周期
Maven 拥有三套相互独立的生命周期,它们分别是: clean 、 default 和 site 。每个生命周期包含一些阶段 (phase),这些阶段是有顺序的,而且后面的阶段依赖于前面的阶段。用户和 Maven 最直接的交互方式是调用这些生命周期的阶段。在调用某一阶段时,该阶段所在的生命周期之前的阶段会首先被执行。但不同周期间的阶段是相互独立的。
2. Clean生命周期
clean 生命周期的目的是清理项目,它包含三个阶段: pre-clean , clean , post-clean 。
关于生命周期的详细介绍,可以参考:http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html。
3. Default生命周期
default 生命周期定义了真正构建时所需要执行的所有步骤,包含如下阶段 :
validate,initialize,generate-soruces,process-sources,generate-resources,process-resources,compile,process-classes,generate-test-sources,process-test-sources,generate-test-resources,process-test-resources,test-compile,process-test-classes,test,prepare-package,package,pre-integration-test,integration-test,post-integration-test,verify,install,deploy。
4. Site生命周期
site生命周期的目的是建立和发布站点,它包含四个阶段:pre-site,site,post-site,site-deploy。
5. 命令行与生命周期
从命令行执行 Maven 任务的最主要方式就是调用 Maven 的生命周期阶段。如 mvn clean deploy site-deploy 调用了clean 生命周期的 clean 阶段(自动触发 clean 之前的依赖: pre-clean )、 default 生命周期的 deploy 阶段(自动触发 deploy 之前的依赖)以及 site 生命周期的 site-deploy 阶段(自动触发 site-deploy 之前的依赖: pre-site , site ,post-site )。
三. 插件目标
插件以独立的构件形式存在,Maven会在需要的时候下载并使用插件。
一个插件可以完成多个任务(功能),每个功能就是一个插件目标(plugin goal)。
如dependency:analyze,冒号前面是插件前缀,冒号后面是该插件的目标。(即dependency:analyze是插件maven-dependency-plugin的analyze目标。)
四. 插件绑定
1. 概述
Maven 生命周期的阶段与插件的目标相互绑定,以完成某个具体的构建任务。
2. 内置绑定
Maven 的核心为一些主要的生命周期阶段默认绑定了很多插件目标,可以参考:
http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Built-in_Lifecycle_Bindings查看具体的绑定关系。由于项目的打包类型会影响构建的具体过程,因此 default 生命周期的阶段与插件目标的绑定关系由项目打包类型决定。
3. 自定义绑定
我们可以自己选择将某个插件目标绑定到生命周期的某个阶段上。
如插件项目的源码jar包,内置的插件绑定关系中并没有涉及该任务。因此需要我们自己配置:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1.1</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
可以将 mven-source-plugin 中的 jar-no-fork 目标(将项目的主代码打包成 jar 文件)绑定到 default生命周期的verify 这个阶段上。
很多插件的目标在编写时已经定义了默认绑定阶段。可以用以下命令查看:
mvn help:describe –Dplugin=org.apache.maven.plugins:maven-source-plugin:2.1.1 –Ddetail
如果多个目标被绑定到同一个阶段,它们的执行顺序由插件声明的先后顺序决定。
五. 插件配置
1. 命令行配置插件
很多插件目标的参数都支持从命令行配置,用户可以在maven命令中使用-D参数, 并伴随一个参数键=参数值的形式来配置插件目标的参数。如:mvn install –Dmaven.test.skip=true
maven.test.skip 是 maven-surefire-plugin 的一个参数,当其值为 true 时,就会跳过执行测试。
2. POM中插件全局配置
有些参数的值从项目创建到项目发布都不会改变或者很少改变,这时,我们可以在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>
该配置告诉 maven-compiler-plugin 要编译的源文件是 Java 1.5 的,并且生成与 JVM 1.5 兼容的字节代码文件。由于 maven-compiler-plugin 被绑定到 compile 与 test-compile 阶段,所以上述配置对这两个阶段都会生效。
3. POM中插件任务配置
我们还可以为某个插件目标及其绑定的某个阶段配置特定的参数:
<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’m 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’m bound to verify phase.</echo>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
以上配置将 maven-antrun-plugin:run 绑定到了 validate 与 verify 两个 phase ,但为两个 phase 设置了不同的参数。
六. 获取插件信息
1. 在线插件信息
基本上所有的插件都来自于 Apache 和 Codehaus 。
可以从插件目标的文档中查阅参数的 Expression 属性,它表示了该参数在命令行中的参数名,如果没有Expression 则说明该插件目标参数只能在 POM 中配置。如:Maven-surefire-plugin 的 skip 参数, Expression 为 :${maven.test.skip} 则在命令行中配置该参数时参数名就为 -Dmaven.test.skip 。而在 POM 中配置时,参数名为 skip 。
我们既可以通过 mvn 命令激活某个生命周期阶段,也可以直接调用某个插件目标,因为有些任务不适合绑定到生命周期阶段上,如: maven-help-plugin:describe , maven-dependency-plugin:tree 。 为了简化插件目标的定位,Maven 引入了插件前缀( Plugin Prefix ),可以用插件前缀替换插件坐标,方便在命令行直接运行插件。如:mvn help:describe –Dplugin=compiler –Dgoal=compile -Ddetail。
2. 使用maven-help-plugin描述插件
七. 从命令行调用插件
八. 插件解析机制
1. 插件仓库
Maven会区别对待依赖的远程仓库与插件的远程仓库。可以在 POM 中配置插件的远程仓库。 Maven 内置的插件仓库配置:
<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Maven Plugin Repository</name>
<url>http://repo1.maven.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshosts>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>
一般来说,中央仓库所包含的插件完全能够满足我们的需要。
2. 插件的默认groupId
在POM中配置插件的时候,可以不配置其groupId,Maven会默认用org.apache.maven.plugins。但不建议这么使用,为了防止团队中不熟悉maven的人困惑。
3. 解析插件版本
Maven在超级 POM中为所有核心插件定义了版本。如果用户使用某个插件而没定义版本时,会使用超级POM中定义的版本,如果这个插件不属于核心插件,Maven2 会解析成lastest而Maven3会解析成release。
4. 解析插件前缀
插件前缀会保存在 groupId/maven-metadata.xml 中。 Maven 在解析插件仓库元数据时,会默认使用org.apahce.maven.plugins 和 org.codehaus.mojo 两个 groupId ,用户可以配置 settings.xml 让 Maven 检查其他groupId 上的插件仓库元数据:
<settings>
<pluginGroups>
<pluginGroup>com.your.plugins</pluginGroup>
</pluginGroups>
</settings>
元数据信息如下:
<metadata>
<plugins>
<plugin>
<name>Maven Clean Plugin</name>
<prefix>clean</prefix>
<artifactId>maven-clean-plugin</artifactId>
</plugin>
…
</plugins>
</metadata>