使用 GraalVM 打包 Native Image

2022-04-24 16:08 更新

dubbo3.0支持native-image文檔

概述

本文檔將介紹將dubbo3.0項目接入GraalVM,進行native-image編譯為二進制的流程。

關于GraalVm的更多信息可以閱讀 https://www.graalvm.org/docs/getting-started/container-images/ 此文檔。

使用樣例

在編譯我們的dubbo項目之前,需要確保我們正基于graalVm的環(huán)境。

  1. 安裝GraalVM

進入https://www.graalvm.org/ 官網(wǎng)根據(jù)自己的系統(tǒng)選取最新版本安裝:

安裝完成后,修改配置JAVA_HOME的路徑,生效后查看本地jdk可以看到如下:

 這里我們使用的基于jdk1.8版本的GraalVM。

  • 安裝native-image,只需執(zhí)行gu install native-image即可。
  1. 拉取dubbo代碼,切換到apache:3.0分支。
  2. 手動執(zhí)行生成SPI代碼。

由于目前編譯native-image不支持代碼動態(tài)生成編譯,所以有關代碼動態(tài)生成的部分需要我們手動先生成,這里提供了工具函數(shù):

 執(zhí)行CodeGenerator即可在dubbo-native模塊下生成SPI代碼。

  1. 在根目錄下執(zhí)行install
MacdeMacBook-pro-3:incubator-dubbo mac$ pwd

/Users/mac/Documents/Mi/project/incubator-dubbo

MacdeMacBook-pro-3:incubator-dubbo mac$ mvn clean package install -Dmaven.test.skip=true
  1. 編譯demo項目

這里我們提供了可直接進行編譯的示例項目,dubbo-demo/dubbo-demo-native。上面步驟install完成后,先到dubbo-demo-native的provider下,執(zhí)行native-image編譯:

 mvn clean package -P native -Dmaven.test.skip=true

這里由于我們在maven中引入了native-image插件,所以直接-P native即可執(zhí)行該插件。

 編譯成功后可以在target下看到已經(jīng)生成的二進制文件,本地啟動一個zookeeper,直接執(zhí)行該二進制,可見啟動成功如下:

 consumer端同樣執(zhí)行編譯,在consumer的target下也會生成二進制文件:demo-native-consumer,執(zhí)行該二進制可以看到調(diào)用結果如下:

具體步驟

實際上在這個demo下我們做了一些工作來確保項目可以編譯執(zhí)行,主要有以下幾個步驟

  • 引入dubbo-native依賴
<dependency>

    <groupId>org.apache.dubbo</groupId>

    <artifactId>dubbo-native</artifactId>

    <version>${project.version}</version>

</dependency>

該模塊下有我們生成的SPI代碼。

  • 引入native-image插件
<plugin>

    <groupId>org.graalvm.nativeimage</groupId>

    <artifactId>native-image-maven-plugin</artifactId>

    <version>21.0.0.2</version>

    <executions>

        <execution>

            <goals>

                <goal>native-image</goal>

            </goals>

            <phase>package</phase>

        </execution>

    </executions>

    <configuration>

        <skip>false</skip>

        <imageName>demo-native-provider</imageName>

        <mainClass>org.apache.dubbo.demo.graalvm.provider.Application</mainClass>

        <buildArgs>

            --no-fallback

            --initialize-at-build-time=org.slf4j.MDC

            --initialize-at-build-time=org.slf4j.LoggerFactory

            --initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder

            --initialize-at-build-time=org.apache.log4j.helpers.Loader

            --initialize-at-build-time=org.apache.log4j.Logger

            --initialize-at-build-time=org.apache.log4j.helpers.LogLog

            --initialize-at-build-time=org.apache.log4j.LogManager

            --initialize-at-build-time=org.apache.log4j.spi.LoggingEvent

            --initialize-at-build-time=org.slf4j.impl.Log4jLoggerFactory

            --initialize-at-build-time=org.slf4j.impl.Log4jLoggerAdapter

            --initialize-at-build-time=org.eclipse.collections.api.factory.Sets

            --initialize-at-run-time=io.netty.channel.epoll.Epoll

            --initialize-at-run-time=io.netty.channel.epoll.Native

            --initialize-at-run-time=io.netty.channel.epoll.EpollEventLoop

            --initialize-at-run-time=io.netty.channel.epoll.EpollEventArray

            --initialize-at-run-time=io.netty.channel.DefaultFileRegion

            --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventArray

            --initialize-at-run-time=io.netty.channel.kqueue.KQueueEventLoop

            --initialize-at-run-time=io.netty.channel.kqueue.Native

            --initialize-at-run-time=io.netty.channel.unix.Errors

            --initialize-at-run-time=io.netty.channel.unix.IovArray

            --initialize-at-run-time=io.netty.channel.unix.Limits

            --initialize-at-run-time=io.netty.util.internal.logging.Log4JLogger

            --initialize-at-run-time=io.netty.channel.unix.Socket

            --initialize-at-run-time=io.netty.channel.ChannelHandlerMask



            --report-unsupported-elements-at-runtime

            --allow-incomplete-classpath

            --enable-url-protocols=http

            -H:+ReportExceptionStackTraces

        </buildArgs>

    </configuration>

</plugin>

其中定義了生成的鏡像名以及一些構建鏡像的參數(shù)。

  • 掛載native-image-agent

由于我們需要將一些反射、JNI等類先指定出來,我們需要先使用該agent以正常方式運行一遍生成這些類的json形式的信息。

在啟動參數(shù)中添加:

-agentlib:native-image-agent=config-output-dir=/tmp/config/,config-write-period-secs=300,config-write-initial-delay-secs=5

以正常方式啟動,在項目的resources下建立文件夾META-INF.native-image,把在本地目錄中生成的文件粘進去:

 (可能會有缺漏沒有生成的類信息,需要根據(jù)編譯或運行時的報錯信息手動添加。)

完成以上幾步后就可以進行項目的編譯了。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號