1. 编写 Maven 插件的主要步骤
1) 创建一个 maven-plugin 项目:插件本身也是 Maven 项目,但它的 packaging 必须为 maven-plugin ,我们可以用 maven-archetype-plugin 快速创建一个 Maven 插件项目。
2) 为插件编写目标: Maven 称之为 Mojo ( Maven Old Java Object )
3) 为目标提供配置点
4) 编写代码实现目标行为:必须提供一个或多个继承自 AbstractMojo 的类。
5) 错误处理及日志
6) 测试插件
2. 可以运行 mvn archetype:generate ,选择:
maven-archetype-plugin ( An archetype which contains a sample Maven Plugin. )
生成插件项目骨架。
3. Maven 插件项目的 POM 有两个特殊的地方:
1) packaging 为 maven-plugin
2) 依赖了 org.apache.maven:maven-plugin-api 提供了插件开发所必需的类。
4. 每个插件目标类,或者说 Mojo 都必须:
1) 继承自 AbstractMojo
2) 实现 execute 方法 ()
3) 在 class 上添加 @goal 标注,定义目标名称
5. 在插件目标类的成员变量上添加 @parameter 标注,表示用户可以在作用该插件的时候在 POM 中配置该字段。如:
@param private String[] includes;
可以在 POM 的该插件配置中添加:
<configuration> <includes> <include>java</include> <include>sql</include> </include> </configuration>
6. 可以用 @param expression=”${project.basedir}” 标注成员变量,表示从系统属性读取字段值。 @readonly 标注表示不允许用户对其进行配置。
7. 实现插件目标类时,当遇到无法处理的 Exception 可以将其包在 MojoExecutionException 中抛出, Maven 执行插件目标的时候,如果遇到 MojoExecutionException ,就会在命令行显示“ BUILD ERROR ”。
8. AbstractMojo 的 getLog() 方法可以返回一个类似 Log4j 的日志对象,可以用来将输出日志到 Maven 命令行。
9. Mojo 标注:
1) @goal <name> 插件目标的名称
2) @phase <phase> 插件目标默认绑定到 default 生命周期的某个阶段
(如 maven-surefire-plugin:test 就有 @phase test 标注)
3) @requiresDependencyResolution <scope> 在运行该 Mojo 之前必须解析所有指定范围的依赖,默认值为 runtime ,可选值为 compile 、 test 和 runtime 。
(如 maven-surefire-plugin:test 就有 @requiresDependencyResolution test 标注)
4) @requiresProject <true/false> 是否必须在一个 Maven 项目中运行,默认为 true 。大多数插件目标都为 true 。但 maven-help-plugin:system 是用来显示系统属性和环境变量的,其值为 false 。还有 maven-archetype-plugin:generate 也不需要在特定项目中运行。
5) @requiresDirectInvocation <true/false> 是否只能在命令行调用,而不能在 POM 中绑定到生命周期阶段。默认为 false 。
6) @requiresOnline <true/false> 是否要求 Maven 是在线状态,默认是 false 。
7) @requiresReport <true/false> 是否要求项目报告已经生成,默认是 false 。
8) @aggregator 当 Mojo 在多模块项目上运行时,只在顶层模块运行。比如 maven-javadoc-plugin:aggregator-jar 只会为多模块项目的顶层项目生成一个已经聚合的 Javadoc 文档。
9) @execute goal= “<goal>” 在运行该目标之前先让 Maven 运行另一个指定目标,如果那个目标也是本插件的目标,则可以省略目标前缀。如 maven-pmd-plugin:check 用来验证 maven-pmd-plugin:pmd 生成的源码分析报告,所以它用了标注 @execute goal=”pmd”
10)@ execute phase=”<phase>” 在运行该目标之前先让 Maven 运行一个并行的生命周期到指定阶段为止。如 maven-dependency-plugin:analyze 使用了标注 @execute phase=”test-compile” 。
11) @execute lifecycle=”<lifecycle>” phase=”<phase>” 在运行该目标之前让 Maven 先运行一个自定义的生命周期到指定阶段为止。如 maven-surefire-report-plugin:report 使用了标注 @execute lifecycle=”surefire” phase=”test” 。自定义生命周期的配置文件位于 src/main/resources/META-INF/maven/lifecycle.xml ,如 :
<lifecycles> <lifecycle> <id>surefire</id> <phases> <phase> <id>test</id> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </phase> </phases> </lifecycle> </lifecycles>
干什么用的?
10. 我们可以用 @parameter 将 Mojo 的某个字段定义为可配置参数,可以在 POM 中配置如下:
1) Boolean 、 boolean:
<param-name>true</param-name>
2) Integer 、 Long 、 Short 、 Byte 、 int 、 long 、 short 、 byte :
<param-name>8</param-name>
3) Float 、 float 、 Double 、 double :
<param-name>8.8</param-name>
4) String 、 StringBuffer 、 Character 、 char :
<param-name>Hello World</param-name>
char 和 Character 会怎么处理?
5) Date :
<param-name>2010-06-06 3:14:55.1 PM</param-name>
或
<param-name>2010-06-06 3:14:55PM</param-name>
6) File :
<param-name>C:\tmp</param-name>
不是路径格式怎么办?
8) URL :
<param-name>http://www.juvenxu.com</param-name>
9) 数组、 Collection
<param-names>
<param-name>value1</param-name>
<param-name>value2</param-name>
</param-names>
10) Map :
<param-name>
<key1>value1</key1>
<key2>value2</key2>
</param-name>
11) Properties :
<param-name>
<property>
<name>name1</name>
<value>value1</value>
</property>
</param-name>
配置的值不法解析成对应格式怎么办?
11. @parameter alias=”<aliasName>” 可以让用户以 aliasName 在 POM 中配置插件参数。
@parameter expression=”${SystemProperty} 可以让用户在命令行配置参数。如 maven-surefire-plugin:test 就有如下代码:
@parameter expression=“${maven.test.skip}”
private boolean skip;
所以用户可以在 POM 中配置 skip 参数,也可以在命令行配置 -Dmaven.test.skip=true 参数。
@parameter default-value=”aValue” 如果用户没有配置该 Mojo 参数,就为其提供一个默认值,可以是常量也可以是表达式。
@readonly 表示参数是只读的。
@required 表示参数是必须的,如果没有配置也没有默认值, Maven 会报错。
12. AbstractMojo 的 execute 方法会抛出两种 Exception :
1) MojoExecutionException ,插件运行时发现了未预期的错误, Maven 会显示“ BUILD ERROR ”
2) MojoFailureException ,插件运行时发现了预期的错误, Maven 会显示“ BUILD FAILURE ”
13. AbstractMojo 的 getLog() 方法得到的 log 对象支持四种级别的日志:
1) debug , Maven 默认不会输出该级别的日志。可以添加 -X 参数开启调试日志。
2) info ,默认会输出。
3) warn ,默认会输出,表示有问题或错误,但不会导致运行失败。
4) error ,默认会输出,表示错误严重到 Mojo 无法继续运行。
14. 测试 Maven 插件,需要有一组实际的 Maven 测试项目,在测试项目的 POM 中配置待测试的 Maven 插件,然后在测试项目上运行 Maven 构建,最后再验证该构建是否成功,且输出是否符合预期。 maven-inoker-plugin 能够用来在一组测试项目上执行 Maven 构建,并检查每个项目的构建是否成功,最后它还可以执行 BeanShell ( http://www.beanshell.org )或 Groovy ( http://groovy.codehaus.org )脚本来验证项目构建的输出。
15. 使 用 maven-invoker-plugin 进行 Maven 插件集成测试的步骤:
1) 在待测试的插件项目的 POM 中配置:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-invoker-plugin</artifactId> <version>1.5</version> <configuration> <projectsDirectory>src/it</projectsDirectory> <goals> <goal>install</goal> </goals> <postBuildHookScript>validate.groovy</postBuildHookScript> </configuration> <executions> <execution> <id>integration-test</id> <phase> integration-test</phase> <goals> <goal>install</goal> <goal>run</goal> </goals> </execution> </executions> </plugin>
projectDirectory 用来配置测试项目的目录,用户可以将测试项目的源码放在 src/it 下。 goals 表示在测试项目上要运行的 Maven 目标。( mvn install ) postBuildHookScript 表示测试项目构建完成后要运行的验证脚本。
以上配置将 maven-invoker-plugin 的两个目标 install 和 run 绑定到了待测试插件的 integration-test 生命周期阶段。 install 目标用来将当前待测试插件项目的构件安装到仓库中供测试项目使用。 run 目标会执行定义好的 mvn 命令构建测试项目并运行验证脚本。
16. maven-invoker-plugin 还有如下配置点:
1) debug(boolean) :是否在构建测试项目的时候开启 debug 输出。
2) settingsFile(File) :执行集成测试所使用的 settings.xml ,默认为本机环境的 settings.xml
3) localRepositoryPath(File) :执行集成测试所使用的本地仓库。
4) preBuildHookScript(String) :构建测试项目之前运行的脚本。
5) postBuildHookScript(String) :构建测试项目之后运行的脚本。
具体可以参考 http://maven.apache.org/plugins/maven-invoker-plugin/