作者:悠悠做神仙
在学习了 【Java工具开发】Maven插件开发之基础篇(一) 后,想必大家对于Maven有了更加深刻的认识,这篇文章将教手把手教大家开发一款Maven插件。
文章目录:
1、创建一个插件项目
2、引入插件开发相关依赖
3、继承插件父类,设置目标
4、绑定到构建生命周期
5、默认可获取的参数
6、参数配置和使用
7、编写核心代码
8、编译打包,安装使用
首先说一下插件开发准备:
(1)安装好Maven,并配置好环境变量以及setting.xml文件。
(2)安装好JDK,并配置好环境变量。
(2)现成的开发工具:idea或eclipse。(本文采用2021.1版Idea)
(3)插件的命名要求了解:自己开发的插件,命名采用 <yourplugin>-maven-plugin
,而不要采用 maven-<yourplugin>-plugin
,因为 它是 Apache Maven 团队维护的官方 Apache Maven 插件的保留命名模式 ,带有 groupId 。使用这种命名模式是对 Apache Maven 商标的侵犯。
在做好相关准备工作之后,我们进入正题:guzhang:~
1、创建一个插件项目
新建一个maven项目。
填写关于项目一些信息。(项目命名最好能体现其功能,比如scan-maven-plugin,就是扫描的插件,我这里仅仅是演示,就先用缩写了)
创建好项目后,进入到项目界面,这时候开始配置maven地址,根据个人之前安装的地址进行选择。
创建包和类。
在pom.xml文件中,更改默认的打包方式。这也就是插件项目不同于一般项目的地方。
<packaging>maven-plugin</packaging>
至此,第一步完成!
2、引入插件开发相关依赖
插件项目开发,有两个最重要的依赖,(当然也有说三个的,后面说第三个),一个是maven插件的api,一个是目标注解的来源。
<dependencies>
<!--插件的抽象类-->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.6.2</version>
</dependency>
<!--MOJO注解的来源-->
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
第三个依赖,有些项目也会用到,今天的演示项目主要是用前两个。
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.6.2</version>
</dependency>
3、继承插件父类,设置目标
org.apache.maven.plugin.AbstractMojo
除了execute
方法之外,该类提供了实现 mojo 所需的大部分基础结构。- 注释“
@Mojo
”是必需的,它控制着 mojo 的执行方式和时间。- 该
execute
方法可以抛出两个异常:
org.apache.maven.plugin.MojoExecutionException
如果出现意外问题。抛出此异常会导致显示“BUILD ERROR”消息。org.apache.maven.plugin.MojoFailureException
如果出现预期问题(例如编译失败)。抛出此异常会导致显示“BUILD FAILURE”消息。
- 该
getLog
方法(在 中定义AbstractMojo
)返回一个类似 log4j 的记录器对象,它允许插件在“调试”、“信息”、“警告”和“错误”级别创建消息。该记录器是向用户显示信息的公认方式。请查看 检索 Mojo Logger 部分以获取有关其正确用法的提示。
这里的 @Mojo
的 name
,就是目标的设置,当然你也可以在注释里面 @goal showProjectInfo
的形式,或者在pom文件中指定,效果是一致的。
对于更多的Mojo 注释,可以参考 Mojo API 规范 。
4、绑定到构建生命周期
根据插件不同的功能,我们可以绑定在相对应的生命周期来触发,比如有些是关于测试的插件,就可以绑定到测试阶段等等。这里演示,绑定到编译阶段。
生命周期的绑定方法也有三种,第一种,就是在 @Mojo
注解上,增加一个 defaultPhase
,并赋值。(如图,可以看到 LifecyclePhase
下的阶段)
方法二,和之前说的goal一样,采用注释的方式。
方法三,是在pom文件中指定。
注:一个插件可以设置多个目标,每个目标都可以绑定到不同的阶段。
5、默认可获取的参数
Maven提供三个隐式变量,用来访问系统环境变量、POM信息和maven的setting, 属于Maven预定义,用户可以直接使用。
${basedir} 表示项目根目录,即包含pom.xml文件的目录;
${version} 表示项目版本;
${maven.build.timestamp} 表示项目构件开始时间;
${maven.build.timestamp.format} 表示属性maven.build.timestamp.format表示属性{maven.build.timestamp}的展示格式,默认值为yyyyMMdd-HHmm,可自定义其格式,其类型可参java.text.SimpleDateFormat。
用法如下:
<properties>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
</properties>
使用pom属性可以引用到pom.xml文件对应元素的值
${project.basedir} 同${basedir};
${project.baseUri} 表示项目文件地址;
${project.build.directory} 表示主源码路径;
${project.build.outputDirectory} 构建过程输出目录,缺省为target/classes;
${project.build.sourceEncoding} 表示主源码的编码格式;
${project.build.sourceDirectory} 表示主源码路径;
${project.packaging} 打包类型,缺省为jar;
${project.version} 表示项目版本,与project.version表示项目版本,与{version}相同。
其他的参数,可以根据pom文件具体的配置,通过${project.xxx}获取任意节点的内容。
6、参数配置和使用
Maven插件的开发,其中注释就是maven插件重要的元数据。
/**
* @goal CustomMavenMojo:表示该插件的服务目标
* @phase compile:表示该插件的生效周期阶段
* @requiresProject false:表示是否依托于一个项目才能运行该插件
* @parameter expression="${name}":表示插件参数,使用插件的时候会用得到
* @required:代表该参数不能省略
*/
对于 parameter
参数,可以参考 Parameter
类:
@Parameter类
public @interface Parameter {
//别名
String alias() default "";
//属性,通过命令行可配置
String property() default "";
//默认值
String defaultValue() default "";
//是否必须,默认false
boolean required() default false;
//是否只读,默认false
boolean readonly() default false;
}
Maven插件的参数,可以通过设置默认值,通过命令行配置,以及可以在pom文件中配置。
支持的格式,也是很丰富。(以下XML是指pom.xml文件)
- 布尔值:包括
boolean
和Boolean
,读取的时候,“true”
会设置成true
,其他文本则是false
。
项目中配置:
/**
* My boolean.
*/
@Parameter
private boolean myBoolean;
pom中配置:
<configuration>
<myBoolean>true</myBoolean>
</configuration>
- 整数:
byte
,Byte
,int
,Integer
,long
,Long
,short
,和Short
。读取配置时,XML 文件中的文本将使用Integer.parseInt()
或valueOf()
适当类的方法转换为整数值。 - 浮点类型:
double
,Double
,float
,和Float
。读取配置时,XML 文件中的文本将使用valueOf()
相应类的方法转换为二进制形式。 - 日期:这包括输入的变量
Date
。读取配置时,XML 文件中的文本将使用以下日期格式之一进行转换:“yyyy-MM-dd HH:mm:ss.S a
”(示例日期为“2005-10-06 2:22:55.1 PM”)或“yyyy-MM-dd HH:mm:ssa
”(示例日期为“2005-10-06 2:22:55PM”)。解析是使用DateFormat.parse()
完成的。 - 文件和目录:包括输入的变量
File
。读取配置时,XML 文件中的文本用作所需文件或目录的路径。如果路径是相对的(不以/
或类似的驱动器号开头C:
),则该路径相对于包含 POM 的目录。 - 网址:包括输入的变量
URL
。读取配置时,使用 XML 文件中的文本作为 URL。格式必须遵循 RFC 2396 准则,并且看起来像任何 Web 浏览器 URL (scheme://host:port/path/to/file
)。 - 纯文本:
char
,Character
,StringBuffer
,和String
。 - 枚举:首先你需要定义你的枚举类型,然后你可以在参数定义中使用枚举类型。 例如:
public enum FileStyle {
XML,
CLASS,
JAVA
}
/**
* My Enum
*/
@Parameter
private FileStyle myFileStyle;
在pom中使用:
<configuration>
<myFileStyle>JAVA</myFileStyle>
</configuration>
- 数组:数组类型参数是通过多次指定参数来配置的。
/**
* My Array.
*/
@Parameter
private String[] myArray;
在pom文件中配置:
<configuration>
<myArray>
<param>value1</param>
<param>value2</param>
</myArray>
</configuration>
- 集合:此类别涵盖任何实现
java.util.Collection
诸如ArrayList
或 的类HashSet
。这些参数是通过多次指定参数来配置的,就像数组一样。
/**
* My List.
*/
@Parameter
private List myList;
在pom文件中配置:
<configuration>
<myList>
<param>value1</param>
<param>value2</param>
</myList>
</configuration>
- map集合:此类别包括它实现的任何类
java.util.Map
,如HashMap
但 不 执行java.util.Properties
。这些参数是通过<span> </span><key>value</key><span> </span>
在参数配置的表单中包含 XML 标签来配置的。
/**
* My Map.
*/
@Parameter
private Map myMap;
在pom文件中配置:
<configuration>
<myMap>
<key1>value1</key1>
<key2>value2</key2>
</myMap>
</configuration>
还要一些不常用的类型,也可以参考 官网 。
7、编写核心代码
我们这里主要是做一个项目信息的打印显示,具体是读取默认参数、pom文件等,进行一个展示。
package com.hundsun.broker;
import org.apache.commons.lang3.StringUtils;
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;
import java.io.File;
import java.util.List;
/**
* @author yyzsx
* @version 1.0.0
* @ProjectName yyzsx-maven-plugin
* @ClassName MyMojo.java
* @Description 演示-输出项目信息
* @createTime 2021年08月08日 13:53:00
*/
@Mojo(name = "showProjectInfo", defaultPhase = LifecyclePhase.COMPILE)
public class MyMojo extends AbstractMojo {
/**
* 项目根路径
*/
@Parameter(defaultValue = "${basedir}", readonly = true, required = true)
private File basedir;
/**
* 获取pom文件中项目版本,或者支持-Dversion=xx,进行传入
*/
@Parameter(property = "version", defaultValue = "${project.version}", readonly = true, required = true)
private String version;
/**
* 获取本地maven仓库地址
*/
@Parameter(defaultValue = "${settings.localRepository}", readonly = true, required = true)
private String localRepository;
/**
* 参数配置,作者
*/
@Parameter(property = "author", defaultValue = "${showProjectInfo.author}", readonly = true, required = true)
private String author;
/***
* 参数集合
*/
@Parameter(property = "lists", readonly = true)
private List lists;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info("*******************ShowProjectInfo*******************");
getLog().info("--------------------MyFirstMojo,begin--------------------");
System.out.println("欢迎语:Hello Maven Plugin");
System.out.println("项目本地仓库localRepository:" + this.localRepository);
System.out.println("项目跟路径basedir:" + basedir);
System.out.println("项目版本version:" + this.version);
System.out.println("项目作者author:" + author);
System.out.println("项目包含文件类型lists:" + StringUtils.join(lists.toArray(), ","));
getLog().info("--------------------MyFirstMojo,end-----------------------");
}
}
8、编译打包,安装使用
调用maven命令,编译打包,主要是 mvn install
或 mvn clean install
。
本项目,先注释掉关于参数配置这一块,然后 mvn install
或 mvn clean install
。
这个时候插件已经安装到本地库,我们的项目,只要在pom中在引用上面这一块,那么就会输出信息了。(这里我还是用这个项目,没换其他项目)
然后重新编译打包一下。 mvn clean install
因为我们绑定在编译阶段,所以这个时候已经可以看到一些项目信息了。
这个时候我们可以调用一下,命令:
mvn com.hundsun:yyzsx-maven-plugin:1.0-SNAPSHOT:showProjectInfo
格式是这样的: mvn groupId:artifactId:version:goal
调用命令感觉太长了?如果你命名符合标准,而且只采用一个默认版本的,那么可以缩写:
原来的是: mvn com.hundsun:yyzsx-maven-plugin:1.0-SNAPSHOT:showProjectInfo
缩写后: mvn yyzsx:showProjectInfo
,即: mvn ${prefix}:goal
效果是一样的。
看到这里,相信大家也开发出了自己的第一款Maven插件!其实插件,只是一种形式,在了解了一些参数配置后,后面写核心代码其实和正常工程是一个样的逻辑。