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

为了更好的阅读本文,请先学习有关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啦!

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容