支持 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/ 官方网站,并根据您的系统选择最新版本进行安装
安装完成后,修改路径配置 JAVA_HOME,并检查其生效后的本地 jdk,您将看到以下内容
这里我们使用基于 jdk1.8 版本的 GraalVM。
- 要安装 native-image,只需执行 gu install native-image。
- 拉取 dubbo 代码并切换到 apache:3.0 分支。
- 手动执行生成的 SPI 代码。
由于当前 native-image 的编译不支持代码动态生成和编译,因此需要手动生成与代码动态生成相关的部分。这里有一个工具函数
执行 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。
编译成功后,您可以在 target 下看到生成的二进制文件,在本地启动一个 zookeeper,并直接执行二进制文件。可以看到启动成功,如下所示
消费者端也执行编译,并在 consumer target 下生成一个二进制文件:demo-native-consumer。执行此二进制文件,您将看到调用结果,如下所示
具体步骤
实际上,我们在该演示中做了一些工作,以确保项目可以编译和执行。主要步骤如下
- 引入 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 的文件夹,并将本地目录中生成的文件粘贴到该文件夹中
(可能存在未生成的缺失类信息,需要根据编译或运行时的错误信息手动添加。)
** 完成上述步骤后,项目即可编译。 **