美文网首页java基础
Maven实战-做一个自己的Maven插件

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

作者: 未城居士 | 来源:发表于2019-07-25 23:12 被阅读0次

    前言

    写本篇文章主要源于看了一下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;
    }
    

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

    相关文章

      网友评论

        本文标题:Maven实战-做一个自己的Maven插件

        本文链接:https://www.haomeiwen.com/subject/rgakrctx.html