maven
中的插件是有很多目标(goal
)组成的,开发插件,实际上就是去编写插件中目标的具体代码。每个目标对应一个java类
,这个类在maven
中叫做MOJO
,maven
提供了一个Mojo的接口
,我们开发插件也就是去实现这个接口的方法,这个接口是:
org.apache.maven.plugin.Mojo
接口有3个方法:
void execute() throws MojoExecutionException, MojoFailureException;
void setLog( Log log );
Log getLog();
说一下上面这个Log
,这是一日志接口,里面定义了很多方法,主要用户向交互者输出日志,比如我们运行mvn clean
,会输出很多提示信息,这些输出的信息就是通过Log
来输出的。
Mojo接口有个默认的抽象类:
org.apache.maven.plugin.AbstractMojo
这个类中把Mojo接口中的setLog和getLog
实现了,而execute
方法没有实现,交给继承者去实现,这个类中Log默认可以向控制台输出日志信息
,maven中自带的插件都继承这个类,一般情况下我们开发插件目标可以直接继承这个类,然后实现execute方法就可以了。
<packaging>maven-pluginpackaging>
<dependency>
<groupId>org.apache.mavengroupId>
<artifactId>maven-plugin-apiartifactId>
<version>3.0version>
dependency>
<dependency>
<groupId>org.apache.maven.plugin-toolsgroupId>
<artifactId>maven-plugin-annotationsartifactId>
<version>3.4version>
<scope>providedscope>
dependency>
org.apache.maven.plugin.AbstractMojo
@Mojo
注解:@org.apache.maven.plugins.annotations.Mojo(name="目标名称")
注意
@Mojo注解
用来标注这个类是一个目标类
,maven
对插件进行构建的时候会根据这个注解来找到这个插件的目标
mvn clean install
mykeHelp 任务定义
@Mojo(name = "mykeHelp")
public class HelpMojo extends AbstractMojo {
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
this.getLog().info("mykeHelp maven plugin start!");
this.getLog().info("mykeHelp 任务 开始处理……");
this.getLog().info("mykeHelp maven plugin end!");
}
}
mykeHelp 任务执行
$ mvn org.myke:maven-plugin:mykeHelp
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building maven-plugin 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-plugin:1.0-SNAPSHOT:mykeHelp (default-cli) @ maven-plugin ---
[INFO] mykeHelp maven plugin start!
[INFO] mykeHelp 任务 开始处理……
[INFO] mykeHelp maven plugin end!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
/**
* 要显示的问候语。
*
*
* @Parameter 注解将变量标识为mojo参数
*/
@Parameter(property = "sayhi.greeting", defaultValue = "Hello World!")
private String greeting;
注解的
defaultValue
参数定义变量的默认值
,此值maven
的属性值,例如“${sayhi.greeting}”
<configuration>
<greeting> myke and mygreeting>
configuration>
上面设置的是一个string类型的greeting参数的值
@Parameter
private boolean myBoolean;
//pom.xml 中配置参数值
<myBoolean>true</myBoolean>
数字类型包含:byte, Byte, int, Integer, long, Long, short, Short,
读取配置时,XML文件中的文本将使用适当类的integer.parseInt()或valueOf()方法
转换为整数值,这意味着字符串必须是有效的十进制整数值,仅由数字0到9组成,前面有一个可选的-表示负值。例子:
@Parameter
private Integer myInteger;
//pom.xml 中配置参数值
<myInteger>10</myInteger>
读取配置时,XML
文件中的文本用作所需文件或目录的路径。如果路径是相对的(不是以/或C:之类的驱动器号开头),则路径是相对于包含POM的目录的。例子:
@Parameter
private File myFile;
//pom.xml 中配置参数值
<myFile>c:\temp</myFile>
public enum Color {
GREEN,
RED,
BLUE
}
/**
* My Enum
*/
@Parameter
private Color myColor;
//pom.xml 中配置参数值
<myColor>GREEN</myColor>
@Parameter
private String[] myArray;
//pom.xml 中配置参数值
<myArray>
<param>value1</param>
<param>value2</param>
</myArray>
@Parameter
private List myList;
//pom.xml 中配置参数值
<myList>
<param>value1</param>
<param>value2</param>
</myList>
@Parameter
private Map myMap;
//pom.xml 中配置参数值
<myMap>
<key1>value1</key1>
<key2>value2</key2>
</myMap>
java.util.Properties
的类型
@Parameter
private Properties myProperties;
//pom.xml 中配置参数值
<myProperties>
<property>
<name>propertyName1</name>
<value>propertyValue1</value>
<property>
<property>
<name>propertyName2</name>
<value>propertyValue2</value>
<property>
</myProperties>
@Parameter
private MyObject myObject;
//pom.xml 中配置参数值
test
项目中使用插件
<plugin>
<groupId>org.mykegroupId>
<artifactId>maven-pluginartifactId>
<version>1.0-SNAPSHOTversion>
<executions>
<execution>
<id>mykeHelp plugin testid>
<phase>pre-cleanphase>
<goals>
<goal>mykeHelpgoal>
goals>
<configuration>
<myBoolean>truemyBoolean>
<myInteger>30myInteger>
<myFile>${project.basedir}myFile>
<myColor>BLUEmyColor>
<myArray>
<array>mavenarray>
<array>springarray>
<array>mybatisarray>
<array>springbootarray>
<array>springcloudarray>
myArray>
<myList>
<list>30list>
<list>35list>
myList>
<myMap>
<name>Javaname>
<age>30age>
myMap>
<myProperties>
<property>
<name>namename>
<value>2020value>
property>
<property>
<name>agename>
<value>30value>
property>
myProperties>
<person>
<name>javaname>
<age>32age>
person>
configuration>
execution>
executions>
plugin>
在使用项目的 pom.xml 插件的目录下执行
mvn pre-clean -Dsayhi.greeting="学习Maven 吧"
执行插件
mvn org.myke:maven-plugin:mykeHelp
mvn 插件groupId:插件artifactId[:插件版本]:插件目标名称
自定义插件前缀的使用
设置自定义插件的artifactId
自定义插件的artifactId满足下面的格式
xxx-maven-plugin
如果采用这种格式的maven会自动将xxx指定为插件的前缀
当我们配置了插件前缀,可以插件前缀来调用插件的目标了,命令如下:
mvn 插件前缀:插件目标
maven默认会在仓库org.apache.maven.plugins
和 org.codehaus.mojo
2个位置查找插件,比如:
mvn clean:help
这个是调用maven-clean-plugin
插件的help
目标,maven-clean-plugin
的前缀就是clean
,他的groupId
是org.apache.maven.plugins
,所以能够直接找到。
但是我们自己定义的插件,如果也让maven能够找到,需要下面的配置。
在~/.m2/settings.xml
中配置自定义插件组
在pluginGroups
中加入自定义的插件组groupId
,如:
<pluginGroup>org.mykepluginGroup>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-shade-pluginartifactId>
<version>3.2.1version>
<executions>
<execution>
<phase>packagephase>
<goals>
<goal>shadegoal>
goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>启动类完整路径mainClass>
transformer>
transformers>
configuration>
execution>
executions>
plugin>
上面使用到了maven官方提供的一个打包的插件,可以将构件打包为可以直接运行的jar包。
自定义一个插件,然后执行上面打包好的插件
插件中需要通过java命令调用打包好的jar包,然后运行
创建自定义目标类
/**
* 插件中需要通过java命令调用打包好的jar包,然后运行
*/
//运行run目标的时候,会先执行构件的 package阶段,也就是先执行项目的打包阶段,打包完成之后才会执行run目标。
@Mojo(name = "run", defaultPhase = LifecyclePhase.PACKAGE)
// @Execute 这个注解可以配置这个目标执行之前可以先执行的生命周期的阶段或者需要先执行的插件目标。
@Execute(phase = LifecyclePhase.PACKAGE)
public class RunMojo extends AbstractMojo {
/**
* 打包好的构件的路径
*/
@Parameter(defaultValue = "${project.build.directory}\\${project.artifactId}-${project.version}.jar")
private String jarPath;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
try {
this.getLog().info("RunMojo Started:" + this.jarPath);
// ProcessBuilder 此类用于创建操作系统进程,它提供一种启动和管理进程
ProcessBuilder builder = new ProcessBuilder("java", "-jar", this.jarPath);
//启动进程
final Process process = builder.start();
new Thread(() -> {
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
try {
String s;
while ((s = reader.readLine()) != null) {
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
//优雅关闭线程
//在JVM销毁前执行的一个线程.
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
RunMojo.this.getLog().info("Destroying...");
process.destroy();
RunMojo.this.getLog().info("Shutdown hook finished.");
}
});
process.waitFor();
this.getLog().info("Finished.");
} catch (Exception e) {
this.getLog().warn(e);
}
}
}
上面这个插件目标的名称为
run
注意这个类上面多了一个注解@Execute
,这个注解可以配置这个目标执行之前可以先执行的生命周期的阶段或者需要先执行的插件目标。
上面配置的是phase = LifecyclePhase.PACKAGE
,也就是说当我们运行上面run
目标的时候,会先执行构件的package阶段
,也就是先执行项目的打包阶段,打包完成之后才会执行run
目标。
mvn clean install
设计你自己的maven插件
ProcessBuilder 用法详解