支持 Graal VM

dubbo3.0 支持 native-image 文档

功能描述

本文档将介绍将 dubbo3.0 项目连接到 GraalVM 并将 native-image 编译成二进制文件的过程。

有关 GraalVm 的更多信息,请阅读 https://graalvm.java.net.cn/docs/getting-started/container-images/ 此文档。

使用场景

如何使用

在编译我们的 dubbo 项目之前,我们需要确保我们基于 graalVm 环境。

安装 GraalVM

访问 https://graalvm.java.net.cn/ 官方网站,并根据您的系统选择最新版本进行安装

img

安装完成后,修改路径配置 JAVA_HOME,并检查其生效后的本地 jdk,您将看到以下内容

img 这里我们使用基于 jdk1.8 版本的 GraalVM。

  • 要安装 native-image,只需执行 gu install native-image。
  1. 拉取 dubbo 代码并切换到 apache:3.0 分支。
  2. 手动执行生成的 SPI 代码。

由于当前 native-image 的编译不支持代码动态生成和编译,因此需要手动生成与代码动态生成相关的部分。这里有一个工具函数

img 执行 CodeGenerator 在 dubbo-native 模块下生成 SPI 代码。

在根目录下执行 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

编译 demo 项目

这里我们提供一个可以直接编译的示例项目,dubbo-demo/dubbo-demo-native。在完成上述安装步骤后,首先进入 dubbo-demo-native 的 provider 并执行 native-image 编译

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

这里,由于我们在 maven 中引入了 native-image 插件,因此可以直接执行插件 -P native。

img 编译成功后,您可以在 target 下看到生成的二进制文件,在本地启动一个 zookeeper,并直接执行二进制文件。可以看到启动成功,如下所示

img 消费者端也执行编译,并在 consumer target 下生成一个二进制文件:demo-native-consumer。执行此二进制文件,您将看到调用结果,如下所示

img

具体步骤

实际上,我们在该演示中做了一些工作,以确保项目可以编译和执行。主要步骤如下

  • 引入 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>

它定义了生成的镜像名称以及构建镜像的一些参数。

  • 挂载 native-image-agent

由于我们需要首先指定一些反射、JNI 等类,因此需要使用 agent 以正常方式运行它,以生成这些类的 json 格式信息。

在启动参数中添加

-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 的文件夹,并将本地目录中生成的文件粘贴到该文件夹中

img (可能存在未生成的缺失类信息,需要根据编译或运行时的错误信息手动添加。)

** 完成上述步骤后,项目即可编译。 **


上次修改时间:2023 年 2 月 23 日:Update for seo / img alt (35090e3f9b4)