前言
虽然,平时工作基本用不到自定义插件,但手动实现一遍还是很有必要.
这样在配置和调用Maven
插件时才能做到知其所以然.
所以本文的标题其实应该是:当我们在使用Maven
插件时我们在使用什么.
简单来说,实现自定义插件,只需要继承maven-plugin-api
工程中的AbastractMojo
并实现无参抽象方法execute
即可.
不过这还不够,因为还需要考虑goal
,phase
和入参等操作.
有两种方式来定义:
1️⃣ JavaDoc
方式
2️⃣ 注解方式: 推荐使用.
实战
使用IDEA可以很方便创建Maven
插件项目:
命名项目:maven-plugin-demo
;
等待工程生成完成,pom.xml
已经引入maven-plugin-api
,同时还生成了一个以JavaDoc
方式实现的自定义插件示例(详见文末附录),故不再赘述,而是以注解形式实现一个自定义插件,它的作用很简单,只是接收参数并打印.
首先引入包含注解的依赖(别忘了还有maven-plugin-api
):
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.5.2</version>
</dependency>
继承AbstractMojo
:
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
@Mojo(name = "hello", defaultPhase = LifecyclePhase.PROCESS_CLASSES)
public class AnnoMojo extends AbstractMojo {
@Parameter(property = "hello.message", required = true, defaultValue = "${project.name}")
private String[] message;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
System.out.println("hello " + String.join("", message) + "~");
}
}
此时插件已经开发完成.
使用
引入依赖
<build>
<plugins>
<plugin>
<groupId>org.example</groupId>
<artifactId>maven-plugin-demo</artifactId>
<version>1.0-SNAPSHOT</version>
</plugin>
</plugins>
</build>
执行mvn -Dhello.message=world,~~ demo:hello
即可实现打印出hello world~~~
的效果.
但一般不会这样显式地单独调用,而是靠clean
,compile
或deploy
等Lifecycle
来触发,其触发关键点在于插件所附着的phase
,它们是有固定的先后顺序的,可以参考官网.
<plugin>
<groupId>org.example</groupId>
<artifactId>maven-plugin-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<executions>
<execution>
<goals>
<goal>hello</goal>
</goals>
<phase>process-sources</phase>
</execution>
</executions>
<configuration>
<message>every body! I'm Ryan</message>
</configuration>
</plugin>
此时执行mvn compile
就会触发插件的hello
目标并打印输出:hello every body! I'm Ryan~
.
小结
executions
元素可以有多个execution
,用来绑定一个phase
和多个goal
.configuration
元素用来配置插件中定义的parameter
拓展
上节中提到了configuration
用来静态配置变量,而命令行可以动态设置,如果同时设置,谁的优先级更高呢?
答案是configuration
元素.
同理,pom
中定义的phase
的优先级高于源码中定义的defaultPhase
总结
- 命名规范:
maven-plugin-XXX
,可以简化命令行调用:mvn XXX:$goal
- packaging:
maven-plugin
- 建议使用注解形式实现,有提示而且排版舒服
- 参数包含空格时的,最好使用数组接收
- 命令行中的参数不会覆盖
pom.xml
中已定义的参数 - 经常变动的参数不要在
configuration
中设置.
附录
-
默认生成的源码:
/** * Goal which touches a timestamp file. * * @goal touch * @phase process-sources */ public class MyMojo extends AbstractMojo { /** * Location of the file. * * @parameter expression="${project.build.directory}" * @required */ private File outputDirectory; public void execute() throws MojoExecutionException { // 此处忽略具体实现 } }