Maven实战-做一个自己的Maven插件

前言

写本篇文章主要源于看了一下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)的概念,能够通过一个中心信息管理项目构建,报告?和文档。简单的理解就是个中心管理项目对象模型的东西。

当然本文的重点是介绍插件构建,首页能够看到

image.png

地址如下

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必要内容

依赖

        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>3.5.3</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>3.6.0</version>
            <scope>provided</scope>
        </dependency>

注意点

image.png

常规的配置这里就不讲, 注意要配置packaging的类型,配置如下:

   <packaging>maven-plugin</packaging>
   <artifactId>hyjal-maven-plugin</artifactId>
   <groupId>com.funnycode.maven.plugin</groupId>
   <version>1.0.0-SNAPSHOT</version>

You will typically name your plugin <yourplugin>-maven-plugin.
Calling it maven-<yourplugin>-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.

如官方所说,我们插件名字选择<yourplugin>-maven-plugin,即artifactId

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 the execute 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的内容,

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-plugin-plugin</artifactId>
                <version>3.4</version>
                <configuration>
                    <!-- 如果使用maven2,就一定要加这一行 -->
                    <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
                </configuration>
                <executions>
                    <execution>
                        <id>mojo-descriptor</id>
                        <goals>
                            <goal>descriptor</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

配置好后,执行mvn clean install就会打到本地仓库

4. 项目引入

在另一个模块的pom中引入

          <plugin>
               <groupId>com.funnycode.maven.plugin</groupId>
               <artifactId>hyjal-maven-plugin</artifactId>
               <version>1.0.0-SNAPSHOT</version>
               <executions>
                   <execution>
                       <phase>compile</phase>
                       <goals>
                           <goal>hyjal</goal>
                       </goals>
                   </execution>
               </executions>
               <configuration>
                   <greeting>welcome</greeting>
               </configuration>
           </plugin>

5. 配置介绍

可以看到上面的<configuration>标签里面有个<greeting>标签,它和代码中的

    @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文件中添加如下配置:
<pluginGroups>
    <pluginGroup>com.funnycode.maven.plugins</pluginGroup>
</pluginGroups>

就可以使用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;
}

我会在后面的文章中一一解惑。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容

  • 转自:http://www.cnblogs.com/crazy-fox/archive/2012/02/09/23...
    晴天哥_王志阅读 2,249评论 2 27
  • 昨天准备就现在开发中的问题写一个Maven插件,完成一些代码的自动生成。在好几年前写过几个插件,这次重新找开看后,...
    jackzh阅读 3,969评论 0 6
  • maven maven是一个跨平台的项目管理的工具。隶属于Apache下的一个开源项目。主要服务于Java平台的项...
    jwfy阅读 883评论 0 2
  • 我们都知道Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编...
    付鹏丶阅读 1,622评论 0 15
  • 生命周期是maven的又一大核心,maven的生命周期是抽象的,而实际行为都是以插件的方式来完成的,下面我将对生命...
    小炼君阅读 1,209评论 0 50