前言
写本篇文章主要源于看了一下yapi接口信息采集代码,此工具就是实现了一个maven插件,然后发现自己对如何开发maven插件好像并不是很熟悉,就趁机学习了一下。maven本身主要功能都插件提供的,因此了解maven插件对学习maven也是很有帮助的。本文通过实现一个简单的插件来讲述如果和开发maven插件,比较简单基础。
Maven简单介绍
引用官网的说明:
Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.
官网 https://maven.apache.org/
可以清晰的看到,Apache Maven是一个软件项目管理和理解工具。它基于项目工程对象建模(POM)的概念,能够通过一个中心信息管理项目构建,报告?和文档。简单的理解就是个中心管理项目对象模型的东西。
当然本文的重点是介绍插件构建,首页能够看到
地址如下
https://maven.apache.org/plugin-developers/index.html
插件简介
Maven大家应该都知道,是一个非常强大的构建工具,生命周期包含项目的:清理,初始化,编译,测试,打包,验证,部署和站点生成等几乎所有的构建步骤,同时,它还是一个依赖管理工具和项目管理工具,帮助我们高效完成这些繁琐的任务,然后大家就可以高高兴兴的写代码了。
而Maven的核心是它的生命周期,但实际上,生命周期又不做任何事情,所有的事情都是交给插件来完成的,每个插件都可以有多个功能,每个功能就是一个插件目标,这种设计思想和模板方法的设计模式比较类似。
例如:我们最常用的命令:mvn clean install,这个命令实际上就使用了maven-clean-plugin和maven-install-plugin插件。目的是清理上一次构建生成的文件并将工程编译打包,安装到maven本地仓库。
开发自己的插件
maven的文档里介绍说,大部分的插件都可以在插件库里面找到,如果实在找不到才需要自己实现一个maven插件,找不到的比例又非常低,据说只有1%(这个具体数字没考证过)
1. pom必要内容
依赖
org.apache.maven
maven-plugin-api
3.5.3
provided
org.apache.maven.plugin-tools
maven-plugin-annotations
3.6.0
provided
注意点
常规的配置这里就不讲, 注意要配置packaging的类型,配置如下:
maven-plugin
hyjal-maven-plugin
com.funnycode.maven.plugin
1.0.0-SNAPSHOT
You will typically name your plugin
-maven-plugin.
Calling it maven--plugin (note "Maven" is at the beginning of the plugin name) is strongly discouraged since it's a reserved naming pattern for official Apache Maven plugins maintained by the Apache Maven team with groupId org.apache.maven.plugins. Using this naming pattern is an infringement of the Apache Maven Trademark.
如官方所说,我们插件名字选择
2. 创建一个mojo类
什么是Mojo?
A Mojo is really just a goal in Maven, and plug-ins consist of any number of goals (Mojos). Mojos can be defined as annotated Java classes or Beanshell script. A Mojo specifies metadata about a goal: a goal name, which phase of the lifecycle it fits into, and the parameters it is expecting.
https://maven.apache.org/guides/introduction/introduction-to-plugins.html
Mojo我们简单的理解就是个Maven的入口目标,注意能够被定义成带注解的Java类。实际列子如下:
@Mojo(name = "hyjal")
public class HyjalPlugin extends AbstractMojo {
@Parameter(defaultValue = "${project.groupId}")
private String groupId;
@Parameter(defaultValue = "${project.artifactId}")
private String artifactId;
@Parameter(defaultValue = "${project.version}")
private String version;
@Parameter(defaultValue = "hello")
private String greeting;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
StringBuilder sb = new StringBuilder();
sb.append(greeting)
.append(":")
.append("groupId:")
.append(groupId)
.append(" artifactId:")
.append(artifactId)
.append(" version:")
.append(version);
this.getLog().info("========================================");
this.getLog().info("==============Hyjal Plugin==============");
this.getLog().info("========================================");
this.getLog().info(sb.toString());
}
}
- The class
org.apache.maven.plugin.AbstractMojo
provides most of the infrastructure required to implement a mojo except for theexecute
method. - The annotation "
@Mojo
" is required and control how and when the mojo is executed. - The
execute
method can throw two exceptions:-
org.apache.maven.plugin.MojoExecutionException
if an unexpected problem occurs. Throwing this exception causes a "BUILD ERROR" message to be displayed. -
org.apache.maven.plugin.MojoFailureException
if an expected problem (such as a compilation failure) occurs. Throwing this exception causes a "BUILD FAILURE" message to be displayed.
-
- 还有个log的这边不做说明
3. 导出插件
在pom增加build的内容,
org.apache.maven.plugins
maven-plugin-plugin
3.4
true
mojo-descriptor
descriptor
org.apache.maven.plugins
maven-compiler-plugin
1.7
配置好后,执行mvn clean install
就会打到本地仓库
4. 项目引入
在另一个模块的pom中引入
com.funnycode.maven.plugin
hyjal-maven-plugin
1.0.0-SNAPSHOT
compile
hyjal
welcome
5. 配置介绍
可以看到上面的
标签里面有个
标签,它和代码中的
@Parameter(defaultValue = "hello")
private String greeting;
字段名称greeting
对应,@Parameter
是属性映射的一个注解,defaultValue是hello,如果不配置Mojo对象的此属性就是hello,而例子中我们设置成welcome
配置的内容比较多,可以查看官方说明如下:
http://maven.apache.org/guides/mini/guide-configuring-plugins.html
6. 插件执行命令
mvn groupId:artifactId:version:goal
我们的测试插件就是
mvn com.gongdao.sample:hyjal-maven-plugin:1.0.0-SNAPSHOT:hyjal
效果如下:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building sample-all-start 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- hyjal-maven-plugin:1.0.0-SNAPSHOT:hyjal (default-cli) @ sample-all-start ---
[INFO] ========================================
[INFO] ==============Hyjal Plugin==============
[INFO] ========================================
[INFO] welcome:groupId:com.funnycode.sample artifactId:sample-all-start version:1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.548s
[INFO] Finished at: Thu Jul 25 13:30:31 CST 2019
[INFO] Final Memory: 7M/309M
7. 简化命令
通过上面的操作,我们需要执行的命令如下:
mvn com.gongdao.sample:hyjal-maven-plugin:1.0.0-SNAPSHOT:hyjal
对于冗长的命令我们肯定用的不舒服,maven提供了几种解决方案:
- mvn com.alibaba.maven.plugins.test:maven-gav-plugin:gav,去掉版本后,会调用本地仓库的最新版本
- maven解析插件仓库元数据时会先找默认的groupId,默认的有:org.apache.maven.plugins和org.codehaus.mojo两个,其次找到对应的artifactId,然后结合当前groupId和最新的版本来确定坐标,即可以将自己的groupId改为:org.apache.maven.plugins或org.codehaus.mojo
- 通过配置settings.xml文件让maven检查其他的groupId上的插件仓库元数据,即在settings文件中添加如下配置:
com.funnycode.maven.plugins
就可以使用mvn hyjal:hyjal
来运行了插件了
8. 插件工程创建
Mojo archetype
mvn archetype:generate \
-DgroupId=sample.plugin \
-DartifactId=hello-maven-plugin \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-plugin
常用插件
大量的插件可以从apache和codehaus获得,还有一些分布在googlecode,sourceforge,github等托管服务中,如Alibaba也有自己的插件库,groupId为:com.alibaba.maven.plugins
结束语
本文只是个简单的入门例子,方便大家的学习。
比如我们看看Mojo的代码有很多属性:
public @interface Mojo {
String name();
LifecyclePhase defaultPhase() default LifecyclePhase.NONE;
ResolutionScope requiresDependencyResolution() default ResolutionScope.NONE;
ResolutionScope requiresDependencyCollection() default ResolutionScope.NONE;
InstantiationStrategy instantiationStrategy() default InstantiationStrategy.PER_LOOKUP;
String executionStrategy() default "once-per-session";
boolean requiresProject() default true;
boolean requiresReports() default false;
boolean aggregator() default false;
boolean requiresDirectInvocation() default false;
boolean requiresOnline() default false;
boolean inheritByDefault() default true;
String configurator() default "";
boolean threadSafe() default false;
}
我会在后面的文章中一一解惑。