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

為了更好的閱讀本文,請(qǐng)先學(xué)習(xí)有關(guān)maven的生命周期、phase、goal相關(guān)知識(shí)??梢撇轿业倪@篇文章:

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

好的,進(jìn)入正題:今天我們來(lái)學(xué)一下自定義maven插件。

在hadoop的源碼中,有一個(gè)module是hadoop-maven-plugins,如下圖:

這個(gè)模塊主要功能是實(shí)現(xiàn)了一個(gè)自定義的maven插件,用來(lái)幫助執(zhí)行cmake,編譯native的代碼并打包成靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)。

因此本文的目標(biāo)有兩點(diǎn):
① 熟悉hadoop打包native庫(kù)的整體過(guò)程
② 從①的過(guò)程中學(xué)習(xí)如果自定義一個(gè)maven plugin

一、Hadoop打包native庫(kù)的過(guò)程

我們?nèi)绻枰幾ghadoop的native本地庫(kù)時(shí),會(huì)執(zhí)行如下命令:

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

注意在-P后面指定了native這個(gè)profile。

因此我們找到了hadoop-common這個(gè)module下的pom.xml里的native profile,如下圖所示:

接下來(lái)我們就拆解這個(gè)profile標(biāo)簽里的內(nèi)容。

profile標(biāo)簽里的build表示了要對(duì)此profile進(jìn)行構(gòu)建。
build標(biāo)簽里面內(nèi)部包含了一些plugin,表示執(zhí)行此build過(guò)程需要用到的插件。
每個(gè)plugin標(biāo)簽里面會(huì)有多個(gè)execution,每個(gè)execution里面的phase標(biāo)簽和goals標(biāo)簽定義了這個(gè)插件的此goal需要綁定到build過(guò)程的哪個(gè)phase,以及一些配置項(xiàng)。

Ok,了解完大概的pom文件標(biāo)簽結(jié)構(gòu)后,我們來(lái)看下插件,注意到有個(gè)插件名字叫:hadoop-maven-plugins。這個(gè)插件是hadoop自己為了打包動(dòng)態(tài)鏈接庫(kù)而實(shí)現(xiàn)的一個(gè)自定義maven插件。

我們?cè)诘诙戮蛠?lái)學(xué)一下這個(gè)插件,然后介紹一下如何自定義maven插件。

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

我先把hadoop-common項(xiàng)目的pom.xml種關(guān)于使用hadoop-maven-plugins的代碼貼出來(lái),后續(xù)分析的時(shí)候可以回看做對(duì)比。

          <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官網(wǎng)中有關(guān)于開(kāi)發(fā)自定義插件的詳細(xì)介紹,真的非常詳細(xì),網(wǎng)址如下:
https://maven.apache.org/guides/plugin/guide-java-plugin-development.html

它會(huì)帶你自己寫(xiě)一個(gè)your first plugin,幾分鐘就搞定,可以嘗試下。
這里我來(lái)介紹一下編寫(xiě)Maven插件的基本步驟,然后再去看hadoop的實(shí)現(xiàn)。

  • 創(chuàng)建 Maven 項(xiàng)目。插件的功能肯定需要編寫(xiě) Java 類(lèi)的,所以插件本身就是一個(gè) Maven 項(xiàng)目。當(dāng)然,相對(duì)于以前研究的 Maven 項(xiàng)目,插件項(xiàng)目有它的特殊點(diǎn):packaging 必須是 maven-plugin 類(lèi)型,可以通過(guò) maven-archetype-plugin 快速創(chuàng)建一個(gè) Maven 插件項(xiàng)目。
  • 編寫(xiě)插件目標(biāo)。每個(gè)插件都至少包含一個(gè)goal,每個(gè)goal對(duì)應(yīng)一個(gè)獨(dú)立的 Java 類(lèi)。這里把這種類(lèi)叫 Mojo 類(lèi)(對(duì)象)。Mojo 類(lèi)必須繼承 AbstractMojo 父類(lèi)。
  • 設(shè)置目標(biāo)的配置點(diǎn)。大部分 Maven 件和它的目標(biāo)都是可以配置的。根據(jù)需要,可以在編寫(xiě) Mojo 的時(shí)候給它設(shè)置好可以配置的參數(shù)。
  • 編寫(xiě)邏輯代碼,實(shí)現(xiàn)目標(biāo)功能。用 Java 代碼實(shí)現(xiàn)插件的功能。
  • 處理錯(cuò)誤和日志。當(dāng) Mojo 運(yùn)行的時(shí)候發(fā)生異常時(shí),需要根據(jù)情況控制 Maven 的運(yùn)行狀況,并且用代碼實(shí)現(xiàn)必要的日志輸出,為用戶提供必要的提示信息。
  • 測(cè)試插件。編寫(xiě)測(cè)試案例,綁定(或命令行)執(zhí)行插件。

好,我們直接來(lái)看Hadoop怎么實(shí)現(xiàn)的。

我們用了cmake-compile這個(gè)goal(可參見(jiàn)上面的pom.xml代碼)。

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

所以找到CompileMojo類(lèi):

簡(jiǎn)單的幾個(gè)注解就搞定。
Map類(lèi)型的變量也支持,例如:

在pom.xml里就對(duì)應(yīng)這些值:

這是如何傳遞個(gè)性化參數(shù)。那執(zhí)行插件的入口在哪呢? 答案是execute方法。自定義的插件所有的phase都要實(shí)現(xiàn)Mojo接口,Mojo接口里有execute方法,是插件的執(zhí)行入口。如下圖所示:

具體到hadoop的CompileMojo類(lèi)的實(shí)現(xiàn)如下:

runCMake方法如下:

當(dāng)然少不了CMakeList.txt文件(編譯C++工程需要用到的,這個(gè)需要手動(dòng)編寫(xiě))

了解了maven如何自定插件之后,我們以后就能自己開(kāi)發(fā)滿足自己項(xiàng)目需求的maven插件了,或者給開(kāi)源的maven插件提merge request啦!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容