美文网首页
【精】聊聊Hadoop自定义的maven插件

【精】聊聊Hadoop自定义的maven插件

作者: 小北觅 | 来源:发表于2021-09-19 00:06 被阅读0次

    为了更好的阅读本文,请先学习有关maven的生命周期、phase、goal相关知识。可移步我的这篇文章:

    【精】讲透Maven-- Build Lifecycle, Phases和 Goals

    好的,进入正题:今天我们来学一下自定义maven插件。

    在hadoop的源码中,有一个module是hadoop-maven-plugins,如下图:

    这个模块主要功能是实现了一个自定义的maven插件,用来帮助执行cmake,编译native的代码并打包成静态库和动态库。

    因此本文的目标有两点:
    ① 熟悉hadoop打包native库的整体过程
    ② 从①的过程中学习如果自定义一个maven plugin

    一、Hadoop打包native库的过程

    我们如果需要编译hadoop的native本地库时,会执行如下命令:

    mvn clean install -Pdist,native -DskipTests -Dmaven.javadoc.skip
    

    注意在-P后面指定了native这个profile。

    因此我们找到了hadoop-common这个module下的pom.xml里的native profile,如下图所示:

    接下来我们就拆解这个profile标签里的内容。

    profile标签里的build表示了要对此profile进行构建。
    build标签里面内部包含了一些plugin,表示执行此build过程需要用到的插件。
    每个plugin标签里面会有多个execution,每个execution里面的phase标签和goals标签定义了这个插件的此goal需要绑定到build过程的哪个phase,以及一些配置项。

    Ok,了解完大概的pom文件标签结构后,我们来看下插件,注意到有个插件名字叫:hadoop-maven-plugins。这个插件是hadoop自己为了打包动态链接库而实现的一个自定义maven插件。

    我们在第二章就来学一下这个插件,然后介绍一下如何自定义maven插件。

    二、hadoop-maven-plugins && 自定义Maven Plugin

    我先把hadoop-common项目的pom.xml种关于使用hadoop-maven-plugins的代码贴出来,后续分析的时候可以回看做对比。

              <plugin>
                <groupId>org.apache.hadoop</groupId>
                <artifactId>hadoop-maven-plugins</artifactId>
                <executions>
                  <execution>
                    <id>cmake-compile</id>
                    <phase>compile</phase>
                    <goals><goal>cmake-compile</goal></goals>
                    <configuration>
                      <source>${basedir}/src</source>
                      <vars>
                        <GENERATED_JAVAH>${project.build.directory}/native/javah</GENERATED_JAVAH>
                        <JVM_ARCH_DATA_MODEL>${sun.arch.data.model}</JVM_ARCH_DATA_MODEL>
                        <REQUIRE_BZIP2>${require.bzip2}</REQUIRE_BZIP2>
                        <REQUIRE_SNAPPY>${require.snappy}</REQUIRE_SNAPPY>
                        <REQUIRE_ZSTD>${require.zstd}</REQUIRE_ZSTD>
                        <CUSTOM_SNAPPY_PREFIX>${snappy.prefix}</CUSTOM_SNAPPY_PREFIX>
                        <CUSTOM_SNAPPY_LIB>${snappy.lib} </CUSTOM_SNAPPY_LIB>
                        <CUSTOM_SNAPPY_INCLUDE>${snappy.include} </CUSTOM_SNAPPY_INCLUDE>
                        <CUSTOM_ZSTD_PREFIX>${zstd.prefix}</CUSTOM_ZSTD_PREFIX>
                        <CUSTOM_ZSTD_LIB>${zstd.lib} </CUSTOM_ZSTD_LIB>
                        <CUSTOM_ZSTD_INCLUDE>${zstd.include} </CUSTOM_ZSTD_INCLUDE>
                        <REQUIRE_ISAL>${require.isal} </REQUIRE_ISAL>
                        <CUSTOM_ISAL_PREFIX>${isal.prefix} </CUSTOM_ISAL_PREFIX>
                        <CUSTOM_ISAL_LIB>${isal.lib} </CUSTOM_ISAL_LIB>
                        <REQUIRE_OPENSSL>${require.openssl} </REQUIRE_OPENSSL>
                        <CUSTOM_OPENSSL_PREFIX>${openssl.prefix} </CUSTOM_OPENSSL_PREFIX>
                        <CUSTOM_OPENSSL_LIB>${openssl.lib} </CUSTOM_OPENSSL_LIB>
                        <CUSTOM_OPENSSL_INCLUDE>${openssl.include} </CUSTOM_OPENSSL_INCLUDE>
                        <EXTRA_LIBHADOOP_RPATH>${extra.libhadoop.rpath}</EXTRA_LIBHADOOP_RPATH>
                      </vars>
                    </configuration>
                  </execution>
                  <execution>
                    <id>test_bulk_crc32</id>
                    <goals><goal>cmake-test</goal></goals>
                    <phase>test</phase>
                    <configuration>
                      <binary>${project.build.directory}/native/test_bulk_crc32</binary>
                      <timeout>1200</timeout>
                      <results>${project.build.directory}/native-results</results>
                    </configuration>
                  </execution>
                  <execution>
                    <id>erasure_code_test</id>
                    <goals><goal>cmake-test</goal></goals>
                    <phase>test</phase>
                    <configuration>
                      <binary>${project.build.directory}/native/erasure_code_test</binary>
                      <timeout>300</timeout>
                      <results>${project.build.directory}/native-results</results>
                      <skipIfMissing>true</skipIfMissing>
                      <env>
                        <LD_LIBRARY_PATH>${LD_LIBRARY_PATH}:${isal.lib}:${isal.prefix}:/usr/lib</LD_LIBRARY_PATH>
                      </env>
                    </configuration>
                  </execution>
                </executions>
              </plugin>
    

    maven官网中有关于开发自定义插件的详细介绍,真的非常详细,网址如下:
    https://maven.apache.org/guides/plugin/guide-java-plugin-development.html

    它会带你自己写一个your first plugin,几分钟就搞定,可以尝试下。
    这里我来介绍一下编写Maven插件的基本步骤,然后再去看hadoop的实现。

    • 创建 Maven 项目。插件的功能肯定需要编写 Java 类的,所以插件本身就是一个 Maven 项目。当然,相对于以前研究的 Maven 项目,插件项目有它的特殊点:packaging 必须是 maven-plugin 类型,可以通过 maven-archetype-plugin 快速创建一个 Maven 插件项目。
    • 编写插件目标。每个插件都至少包含一个goal,每个goal对应一个独立的 Java 类。这里把这种类叫 Mojo 类(对象)。Mojo 类必须继承 AbstractMojo 父类。
    • 设置目标的配置点。大部分 Maven 件和它的目标都是可以配置的。根据需要,可以在编写 Mojo 的时候给它设置好可以配置的参数。
    • 编写逻辑代码,实现目标功能。用 Java 代码实现插件的功能。
    • 处理错误和日志。当 Mojo 运行的时候发生异常时,需要根据情况控制 Maven 的运行状况,并且用代码实现必要的日志输出,为用户提供必要的提示信息。
    • 测试插件。编写测试案例,绑定(或命令行)执行插件。

    好,我们直接来看Hadoop怎么实现的。

    我们用了cmake-compile这个goal(可参见上面的pom.xml代码)。

    <goals><goal>cmake-compile</goal></goals>
    

    所以找到CompileMojo类:

    简单的几个注解就搞定。
    Map类型的变量也支持,例如:

    在pom.xml里就对应这些值:

    这是如何传递个性化参数。那执行插件的入口在哪呢? 答案是execute方法。自定义的插件所有的phase都要实现Mojo接口,Mojo接口里有execute方法,是插件的执行入口。如下图所示:

    具体到hadoop的CompileMojo类的实现如下:

    runCMake方法如下:

    当然少不了CMakeList.txt文件(编译C++工程需要用到的,这个需要手动编写)

    了解了maven如何自定插件之后,我们以后就能自己开发满足自己项目需求的maven插件了,或者给开源的maven插件提merge request啦!

    相关文章

      网友评论

          本文标题:【精】聊聊Hadoop自定义的maven插件

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