本文部分内容来源于Maven官方网址:https://maven.apache.org/plugin-developers/index.html
Maven
实际上是Maven Plugin集合的核心框架,而Plugin是Maven执行实际操作的关键,例如常见的插件:创建Jar文件、创建WAR文件、编译代码、单元测试、创建项目文档等.你可以想象到的对项目执行的所有操作几乎都是Maven Plugin来执行的.
Maven Plugin的实际上是由一个或多个MOJO组成
MOJO来源于POJO(Plain-Old-Java-Object),而M所代表的是Maven的意思
所以Maven插件的Mojo所代表的意思:Maven Plain Old Java Object
所以在Maven Plugin中的核心组成实际上就是一组简单的MOJO
既然MOJO是Maven的插件核心实体类,那么我们开发自己的Maven插件只需要创建Maven的POJO就可以了
以Apache官方团队维护的Maven插件命名风格是maven-
,通常我们自己开发Maven插件不能使用这种命名,这种命名模式是对Apache Maven商标的侵犯
第三方Maven插件的命名规范:
要开发一个Maven插件,首先第一步是新建MOJO实体类,通过继承AbstractMojo
类,并重写该类的execute
方法,通过注解@Mojo
标注这是一个Maven插件,如下代码:
package sample.plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
/**
* Maven Plugin HelloWorld
*
*/
@Mojo( name = "hello")
public class GreetingMojo extends AbstractMojo
{
public void execute() throws MojoExecutionException
{
//会在执行该Plugin时,在控制台进行打印输出
System.out.println("Hello Maven Plugin");
}
}
Maven插件实际上也是一组jar项目,但是项目类型会所有不同,主要区别:
1、按照规定的maven插件命名风格进行命名
2、我们在Maven插件项目中,在pom.xml
文件需要将packagin
类型设置为maven-plugin
3、需要添加Apache Maven官方提供的插件依赖,例如上面的@Mojo
注解就来源于maven-plugin-annotations
jar包
pom.xml
示例如下:
<project>
<modelVersion>4.0.0modelVersion>
<groupId>sample.plugingroupId>
<artifactId>hello-maven-pluginartifactId>
<version>1.0-SNAPSHOTversion>
<packaging>maven-pluginpackaging>
<name>Sample Parameter-less Maven Pluginname>
<dependencies>
<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>
dependencies>
project>
我们在开发完成Maven插件后,需要执行Maven Install命令,将Maven插件安装在本地Maven仓库中,然后在项目中就可以使用了
我们在项目中的
节点添加我们开发完成的Maven插件即可使用,如下:
<plugin>
<groupId>org.examplegroupId>
<artifactId>hello-maven-pluginartifactId>
<version>1.0version>
plugin>
此时,在项目的命令行,可以通过执行命令mvn hello:hello
执行我们的插件
这里的命令所代表的含义:mvn pluginName:mojoName
第一个hello
是因为我们的插件是以hello-maven-plugin
进行命名的,这也是Maven插件的简写方式
第二个hello
是因为@Mojo
注解中定义的name名称
@Mojo( name = "hello")
public class GreetingMojo extends AbstractMojo
{
//more...
}
####2.4.2在settings.xml
全局文件中添加插件引用
我们可以在${user.home}/.m2/settings.xml
配置文件中添加我们的插件groupId,例如:
<pluginGroups>
<pluginGroup>org.examplepluginGroup>
pluginGroups>
这样即使我们不在项目的pom.xml
中引用插件,依然可以全局执行该插件
我们可以指定我们的插件在Maven项目构建时某一个周期(compile
,package
等等)时执行
例如以下配置,指定我们的插件在项目compile
阶段执行我们的插件操作
<plugin>
<groupId>org.examplegroupId>
<artifactId>hello-maven-pluginartifactId>
<version>1.0version>
<executions>
<execution>
<phase>compilephase>
<goals>
<goal>hellogoal>
goals>
execution>
executions>
plugin>
我们通常在使用Maven插件时,需要将外部参数传入插件中,插件根据传入配置文件进行初始化,然后执行操作
例如Mybatis的代码生成插件,配置如下:
<plugin>
<groupId>org.mybatis.generatorgroupId>
<artifactId>mybatis-generator-maven-pluginartifactId>
<version>1.3.2version>
<configuration>
<configurationFile>src/main/resources/generator/generatorConfig.xmlconfigurationFile>
<overwrite>trueoverwrite>
<verbose>trueverbose>
configuration>
plugin>
在mybatis的generator插件中,会有参数的定义,通过@Parameter
注解进行引用,代码如下:
@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES,
requiresDependencyResolution = ResolutionScope.TEST)
public class MyBatisGeneratorMojo extends AbstractMojo {
private ThreadLocal<ClassLoader> savedClassloader = new ThreadLocal<>();
/**
* Maven Project.
*
*/
@Parameter(property = "project", required = true, readonly = true)
private MavenProject project;
/**
* Location of the configuration file.
*/
@Parameter(property = "mybatis.generator.configurationFile",
defaultValue = "${project.basedir}/src/main/resources/generatorConfig.xml", required = true)
private File configurationFile;
//more....
}
Maven插件通过参数外置,对于Maven插件来说是非常有用的,参数提供两个非常重要的功能:
在Maven插件中定义插件非常简单,只需要使用@Parameter
注解即可,例如:
/**
* The greeting to display.
*/
@Parameter( property = "hello.greeting", defaultValue = "Hello World!" )
private String greeting;
defaultValue
所代表的是参数的默认值,开发者可以使用项目引用的表达式进行配置,例如${project.version}
等
关于项目引用的表达式配置,更多的信息请参考PluginParameterExpressionEvaluator
property
属性通过引用用户通过-D
选项设置的系统属性,该参数运行从命令行配置Mojo参数
在Maven的Mojo中定义好参数后,我们在Maven的pom.xml
文件中引用插件时,可以通过configuration
节点添加参数的引用,示例如下:
<plugin>
<groupId>org.examplegroupId>
<artifactId>hello-maven-pluginartifactId>
<version>1.0version>
<configuration>
<greeting>Welcomegreeting>
configuration>
plugin>
####3.3.1布尔类型(Boolean)
在Mojo中定义布尔类型的参数变量,代码如下:
/**
* My boolean.
*/
@Parameter
private boolean myBoolean;
在配置文件中添加引用
<myBoolean>truemyBoolean>
只有配置了true
的情况下,myBoolean
变量为真,其他情况该变量的值都是false
####3.3.2数值类型(Integer)
数值类型包含的类型:byte
、Byte
、int
、Integer
、long
、Long
、short
、Short
当读取configuration节点中的配置属性时,会调用Integer.parseInt()
方法或者valueOf()
方法进行将文本数值进行转换(如果类型是Integer
的话),这意味着配置的数值类型必须是合法的
Mojo中参数定义
/**
* My Integer.
*/
@Parameter
private Integer myInteger;
在配置文件中添加引用
<myInteger>10myInteger>
####3.3.3浮点型类型(Float)
浮点类型包含double
、Double
、float
、Float
类型,同整数类型,读取配置文件时会调用valueOf()
方法进行转换
Mojo中参数定义:
/**
* My Double.
*/
@Parameter
private Double myDouble;
在配置文件中添加引用
<myDouble>1.0myDouble>
####3.3.4日期类型(Date)
日期类型需要传入指定格式:yyyy-MM-dd HH:mm:ss.S a
或者yyyy-MM-dd HH:mm:ssa
读取配置文件时最终是通过调用DateFormat.parse()
方法进行转换
Mojo中参数定义:
/**
* My Date.
*/
@Parameter
private Date myDate;
在配置文件中添加引用
<myDate>2005-10-06 2:22:55.1 PMmyDate>
####3.3.5文件和文件夹(File)
可以配置File类型,如果配置的路径不是以根目录开始的(非/
开头或者不是以盘符C:
等开头),则该文件时相对于项目的pom.xml
引用的相对路径
Mojo中参数定义
/**
* My File.
*/
@Parameter
private File myFile;
在配置文件中添加引用
<myFile>c:\tempmyFile>
####3.3.6链接(URL)
URL
类型,配置的格式必须遵循RFC 2396
准则,并且类似于任何Web浏览器URL,在进行转换时,对URL的内容没有任何限制
Mojo中参数定义
/**
* My URL.
*/
@Parameter
private URL myURL;
在配置文件中添加引用
<myURL>http://maven.apache.orgmyURL>
文本字符主要包含的类型包括:char
、Character
、StringBuffer
、String
枚举类型同样可以使用,首先你得在你的Plugin中定义枚举,然后才能使用,例如枚举的定义如下:
public enum Color {
GREEN,
RED,
BLUE
}
/**
* My Enum
*/
@Parameter
private Color myColor;
在配置文件中引用
<myColor>GREENmyColor>
当然,你也可以通过defaultValue
默认值进行引用,如下:
public enum Color {
GREEN,
RED,
BLUE
}
/**
* My Enum
*/
@Parameter(defaultValue = "GREEN")
private Color myColor;
下面列出了各种类型的复合对象,他们可以作为mojo中的参数
在Mojo类中定义如下:
/**
* My Array.
*/
@Parameter
private String[] myArray;
在配置文件引用:
<myArray>
<param>value1param>
<param>value2param>
myArray>
在Java中主要实现java.util.Collection
接口的集合类,例如ArrayList
或者HashSet
等
Mojo类中定义如下:
/**
* My List.
*/
@Parameter
private List myList;
在配置文件中引用:
<myList>
<param>value1param>
<param>value2param>
myList>
对于键值对类型主要是以实现java.util.Map
类型的类型,例如HashMap
,但是这里不包含java.util.Properties
定义规则
在Mojo类中定义如下:
/**
* My Map.
*/
@Parameter
private Map myMap;
在配置文件中引用:
<myMap>
<key1>value1key1>
<key2>value2key2>
myMap>
针对配置文件的类型java.util.Properties
,配置的规则有所不同
定义规则:
<property>
<name>myNamename>
<value>myValuevalue>
property>
在Mojo中的定义如下:
/**
* My Properties.
*/
@Parameter
private Properties myProperties;
在配置文件中引用:
<myProperties>
<property>
<name>propertyName1name>
<value>propertyValue1value>
<property>
<property>
<name>propertyName2name>
<value>propertyValue2value>
<property>
myProperties>
通过阅读上面的章节内容,我们要开发一个基本的能工作的插件基本需要使用到2个核心注解,分别是:
@Mojo
:定义一个Maven插件的Mojo标志注解
@Parameter
:该Mojo中所需要引用的外部参数
@Mojo
注解完整请参考:http://maven.apache.org/developers/mojo-api-specification.html#The_Descriptor_and_Annotations
示例代码:
/**
* Mojo Description. @Mojo( name = "" ) is the minimal required annotation.
* @since
* @deprecated
*/
@Mojo( name = "" ,
aggregator = <false|true>,
configurator = "" ,
executionStrategy = "" ,
inheritByDefault = <true|false>,
instantiationStrategy = InstantiationStrategy.<strategy>,
defaultPhase = LifecyclePhase.<phase>,
requiresDependencyResolution = ResolutionScope.<scope>,
requiresDependencyCollection = ResolutionScope.<scope>, // (since Maven 3.0)
requiresDirectInvocation = <false|true>,
requiresOnline = <false|true>,
requiresProject = <true|false>,
requiresReports = <false|true>, // (unsupported since Maven 3.0)
threadSafe = <false|true> ) // (since Maven 3.0)
@Execute( goal = "" ,
phase = LifecyclePhase.<phase>,
lifecycle = "" )
public class MyMojo
extends AbstractMojo
{
//more...
}
先来看@Mojo
注解的源码,定义的属性
@Documented
@Retention( RetentionPolicy.CLASS )
@Target( ElementType.TYPE )
@Inherited
public @interface Mojo
{
/**
* goal name (required).
* @return the goal name
*/
String name();
/**
* default phase to bind your mojo.
* @return the default phase
*/
LifecyclePhase defaultPhase() default LifecyclePhase.NONE;
/**
* the required dependency resolution scope.
* @return the required dependency resolution scope
*/
ResolutionScope requiresDependencyResolution() default ResolutionScope.NONE;
/**
* the required dependency collection scope.
* @return the required dependency collection scope
*/
ResolutionScope requiresDependencyCollection() default ResolutionScope.NONE;
/**
* your Mojo instantiation strategy. (Only per-lookup
and singleton
are supported)
* @return the instantiation strategy
*/
InstantiationStrategy instantiationStrategy() default InstantiationStrategy.PER_LOOKUP;
/**
* execution strategy: once-per-session
or always
.
* @return once-per-session
or always
*/
String executionStrategy() default "once-per-session";
/**
* does your mojo requires a project to be executed?
* @return requires a project
*/
boolean requiresProject() default true;
/**
* does your mojo requires a reporting context to be executed?
* @return requires a reporting context
*/
boolean requiresReports() default false;
/**
* if the Mojo uses the Maven project and its child modules.
* @return uses the Maven project and its child modules
*/
boolean aggregator() default false;
/**
* can this Mojo be invoked directly only?
* @return invoked directly only
*/
boolean requiresDirectInvocation() default false;
/**
* does this Mojo need to be online to be executed?
* @return need to be online
*/
boolean requiresOnline() default false;
boolean inheritByDefault() default true;
/**
* own configurator class.
* @return own configurator class
*/
String configurator() default "";
/**
* is your mojo thread safe (since Maven 3.x)?
* @return is thread safe
*/
boolean threadSafe() default false;
}
其实通过注释,我们基本已经能知道部分属性的含义,详细说明如下:
定义Maven插件的goal名称,我们一般在项目中使用Maven插件时如下Xml:
<plugin>
<groupId>org.examplegroupId>
<artifactId>hello-maven-pluginartifactId>
<version>1.0version>
<executions>
<execution>
<phase>compilephase>
<goals>
<goal>hellogoal>
goals>
execution>
executions>
plugin>
该属性代表默认在Maven那个生命周期(常见的compile
、package
、install
等等)时执行,对于自定义开发的Maven插件,一般默认是None
,即不指定
Xml配置
<plugin>
<groupId>org.examplegroupId>
<artifactId>hello-maven-pluginartifactId>
<version>1.0version>
<executions>
<execution>
<phase>compilephase>
<goals>
<goal>hellogoal>
goals>
execution>
executions>
plugin>
####4.1.3requiresDependencyResolution
指定Maven插件依赖jar包的Scope(常见的如test
,runtime
,compile
等)范围,该值是一个枚举
枚举定义如下:
枚举值 | 说明 |
---|---|
None |
空 |
COMPILE |
所规定的依赖scope范围是compile +system +provided |
COMPILE_PLUS_RUNTIME |
在上面COMPILE 的基础上加上runtime |
RUNTIME |
所规定的scope范围是compile +runtime |
RUNTIME_PLUS_SYSTEM |
在RUNTIME 的基础上添加system |
TEST |
该值几乎涵盖所有,范围是compile +system +provided +runtime +test |
如果指定为默认的None
,则范围默认为RUNTIME
Flags this mojo as requiring information about the dependencies that would make up the specified class path. As the name suggests, this annotation is similar to @requiresDependencyResolution
and supports the same values for . The important difference is that this annotation will not resolve the files for the dependencies, i.e. the artifacts associated with a Maven project can lack a file. As such, this annotation is meant for mojos that only want to analyze the set of transitive dependencies, in particular during early lifecycle phases where full dependency resolution might fail due to projects which haven’t been built yet. A mojo may use both this annotation and @requiresDependencyResolution
at the same time. The resolution state of any dependency that is collected but not requested to be resolved is undefined. Since Maven 3.0.
你的Maven插件Mojo实例化策略,该值是一个枚举类型
@Parameter
注解@Parameter
注解所代表的是我们的插件Mojo所需要的外部参数定义,可以通过外部参数传入的方式让我们的插件更健壮
参数的名称,默认使用java字段名
指定参数的别名,此选项让我们在配置configuration
节点时可以根据参数的别名配置参数值
property
参数存在的意义是运行我们通过命令行使用Maven插件时,通过-D
参数指定Mojo中的属性进行赋值,从而使Mojo完成工作
即不需要通过在项目的pom.xml
中添加plugin来使用Maven插件
例如执行我们的第一个插件时(在全局settings.xml
配置pluginGroup
节点)
mvn hello:hello -DparameterName=test
参数的默认值
该参数值是否必须
该参数指定我们的Mojo中的属性不能由用户直接配置(例如在pom.xml
中指定)
例如我们需要使用到和本工程相关的参数来作为最终输出参数,如下:
@Parameter(property = "project", required = true, readonly = true)
private MavenProject project;
根据Maven Plugin的开发思想,开发了一个模板工厂template-factory
的Maven Plugin
目前在工作中,碰到了越来越多的可重复性代码,每次针对一个新的需求时,都需要重新手写一遍(service\controller\vo\dto等),极其繁琐,因此开发了template-factory
项目地址:https://gitee.com/dt_research_institute/template-factory