Graalvm Native Image 元数据适配

news2024/11/15 7:01:10

Graalvm Native Image 元数据适配


本文章主要叙述在 Java 应用适配 Graalvm Native Image 中的步骤和遇到的一些问题!因为 Graalvm 官方文档相关概念叙述过于简单。基本靠问才能知道些许有用信息。所以写此文章。

关于 Graalvm 基础知识的相关学习,可以参照 Seata 社区 commiter 王良的 Blog,本文章主要介绍元数据适配。不对 Graalvm 基础做过多介绍。

Graalvm 现状介绍

GraalVM:是一种高性能运行时,可显着提高应用程序性能和效率,是微服务的理想选择。它专为使用 Java、JavaScript、基于 LLVM 的语言(例如 C 和 C++)以及其他动态语言编写的应用程序而设计。它消除了编程语言之间的隔离,并在共享运行时实现了互操作性。它可以独立运行,也可以在 OpenJDK、Node.js 或 Oracle 数据库的上下文中运行。

Graalvm 主要涉及到 VmWare,RedHat 和 Oracle Labs 三家。RedHat 主要是直接参与 Graalvm 本体,VmWare参与的是 metadata 和 nativeTest,Oracle Labs作为主导方什么都干。

Native Image:**是一种提前将 Java 代码编译为二进制文件(本机可执行文件)的技术。本机可执行文件仅包含运行时所需的代码,即应用程序类、标准库类、语言运行时和来自 JDK 的静态链接本机代码。**它是 Oracle 官方首推的 Java AoT 解决方案,通过C语言实现了一个超微缩的运行时组件 —— Substrate VM,基本实现了 JVM 的各种特性,但足够轻量、可以被轻松内嵌,这就让 Java 语言和工程摆脱 JVM 的限制,能够真正意义上实现和 C/C++ 一样的 AoT 编译。这一方案在经过长时间的优化和积累后,已经拥有非常不错的效果。

Native Image 工具依赖于在运行时对应用程序可访问代码类的静态分析。但是,分析不能总是完全预测 Java 本机接口 (JNI)、Java 反射、动态代理对象或类路径资源的所有用法。必须以元数据 native-image 的形式(在代码中预先计算或作为 JSON 配置文件)向工具提供未检测到的这些动态功能的使用情况。

在项目中打包二进制文件时,需要使用到 JSON 配置文件,关于怎么获取相关配置和保证获取到的配置正确性,以及如何存放相关的元数据配置文件是目前需要迫切解决的问题!

相关概念

因为本文章主要介绍 Native Image 相关,所以只对在使用 Native Image 相关功能中用到的名词做解释!

插件相关

  1. nbt:graalvm native build tools 插件简称;
  2. tck plugin:Oracle 官方提供涉及元数据检测的 gradle 插件。

配置相关

  1. agent:GraalVM 提供的一个 Tracing Agent 来轻松收集元数据和准备配置文件;

  2. conditional mode:条件代理模式生成带有条件的元数据;

  3. standard mode:agent 默认选项,标准代理模式无条件生成元数据;

  4. direct mode:直接代理模式允许用户直接将选项传递给代理,(涉及到 tck 的诡异单元测试);

  5. experimental-conditional-config-filter-file:被认为包含在这个过滤器中的类将被指定为用户代码类;

  6. conditional-config-class-filter-file:要进一步过滤生成的配置;

  7. access-filter-file:访问过滤器适用于访问的目标。因此,访问过滤器可以直接从生成的配置中排除包和类(及其成员);

  8. caller-filter-file:过滤机制通过识别执行访问的 Java 方法(也称为调用方方法)并将其声明类与一系列过滤规则相匹配来工作;

  9. graalvm reachability metadata:graalvm 官方元数据中央仓库;

  10. imagecode:graalvm 本体的系统属性,相关文档中没有提及,服务于 nbt 的识别。Spring Context Framework NativeTest 靠此属性识别(涉及到 Oracle Labs 希望最小化这种属性判定影响的争议)。

  11. 特别注意的是:目前 access-filter 和 caller-filter 仅对 standard mode 起作用

关于 conditional mode 和 standard mode。,direct mode 只有以下几个仓库依稀记录,其他靠问!

  • https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html
  • https://github.com/graalvm/native-build-tools
  • 核心来源:https://www.graalvm.org/latest/reference-manual/native-image/metadata/AutomaticMetadataCollection/
  • imagecode参考:
    1. https://junit.org/junit5/docs/current/api/org.junit.jupiter.api/org/junit/jupiter/api/condition/EnabledInNativeImage.html
    2. https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java
    3. 最近一次 pr 参考,spring framework 6.0.9 对 native build tools 做的关键改动:https://github.com/spring-projects/spring-framework/issues/30511 ,https://github.com/spring-projects/spring-framework/issues/30281

以上相关概念均可在上面的链接中找到相关叙述!

以 Nacos 为例生成元数据文件

maven

graalvm 社区并没有使用 maven 作为插件管理工具,而是使用 gradle。因为 nbt 目前还没有支持 maven 3.9.0+, 同时相比 gradle plugin 存在线程安全问题,尤其是尝试在多模块并行执行 metadatacopy goal 时必定失败!

创建项目

参考 Demo: https://github.com/yuluo-yx/graalvm-demo

项目插件介绍及配置

在 pom.xml 中加入如下配置:

<profiles>
   <profile>
      <id>native</id>
      <build>
         <pluginManagement>
            <plugins>
               <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
                  <configuration>
                     <jvmArguments>
                        -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image/,experimental-conditional-config-filter-file=src/main/resources/conditional-filter.json,access-filter-file=src/main/resources/user-code-filter.json
                        <!-- 被认为包含在这个过滤器中的类将被指定为用户代码类 -->
                        <!--experimental-conditional-config-filter-file=src/main/resources/user-code-filter.json,-->
                        <!-- 要进一步过滤生成的配置 -->
                        <!-- conditional-config-class-filter-file=<path> -->
                        <!-- 访问过滤器适用于访问的目标。因此,访问过滤器可以直接从生成的配置中排除包和类(及其成员)。 -->
                        <!--access-filter-file=src/main/resources/conditional-filter.json-->
                        <!-- 过滤机制通过识别执行访问的 Java 方法(也称为调用方方法)并将其声明类与一系列过滤规则相匹配来工作 -->
                        <!--caller-filter-file=src/main/resources/-->
                     </jvmArguments>
                     <image>
                        <builder>paketobuildpacks/builder:tiny</builder>
                        <env>
                           <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                        </env>
                     </image>

                  </configuration>
                  <executions>
                     <execution>
                        <id>process-aot</id>
                        <goals>
                           <goal>process-aot</goal>
                        </goals>
                     </execution>
                  </executions>
               </plugin>
               <plugin>
                  <groupId>org.graalvm.buildtools</groupId>
                  <artifactId>native-maven-plugin</artifactId>
                  <configuration>
                     <!--<agent>
                     <enabled>true</enabled>
                     <defaultMode>conditional</defaultMode>
                     <modes>
                     <conditional>
                     <userCodeFilterPath>src/main/resources/user-code-filter.json</userCodeFilterPath>
                     </conditional>
                     </modes>
                     </agent>-->
                     <classesDirectory>${project.build.outputDirectory}</classesDirectory>
                     <!-- 需要修改成为自己本地的 元数据仓库地址,不然报错  此配置是为了本地调试方便 -->
                     <metadataRepository>
                        <enabled>true</enabled>
                        <localPath>
                           E:\Java\apache_maven\apache-maven-3.9.0\repository\org\graalvm\buildtools\graalvm-reachability-metadata\0.9.19\graalvm-reachability-metadata-0.9.19-repository.zip
                        </localPath>
                     </metadataRepository>
                     <requiredVersion>22.3</requiredVersion>
                  </configuration>
                  <executions>
                     <execution>
                        <id>add-reachability-metadata</id>
                        <goals>
                           <goal>add-reachability-metadata</goal>
                        </goals>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </pluginManagement>
      </build>
   </profile>
</profiles>

项目元数据生成

项目配置完成之后,在 terminal 执行如下命令:

mvn clean -Pnative spring-boot:run

即可在 resource 目录下看到生成的相关元数据文件。

gradle

gradle 对 spring context framework 并不友好,可能跑不通 nativeTest,中央仓库中有带着 spring framework。带着 spring boot 目前没有跑通 agent 的 test!

参考 url:

  • https://github.com/spring-projects/spring-framework/issues/30281
  • https://github.com/oracle/graalvm-reachability-metadata/pull/154

创建项目

参考 Demo:https://github.com/yuluo-yx/nacos-client-metadata

项目插件介绍及配置

gradle nbt plugin:https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html#_introduction

NBT 插件的本质是拼接 shell 命令!

build.gradle 配置文件示例:

// 引入插件
plugins {
	id 'java'
	id 'org.graalvm.buildtools.native' version '0.9.22'
}

group 'indi.yuluo'
version '1.0-SNAPSHOT'

repositories {
    // 配置 maven 中央仓库
	maven { url 'https://maven.aliyun.com/repository/public' }
	mavenCentral()
	gradlePluginPortal()
}

dependencies {
    testImplementation 'com.alibaba.nacos:nacos-client:2.2.1'
    testImplementation 'org.assertj:assertj-core:3.22.0'
    testImplementation 'org.awaitility:awaitility:4.2.0'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}

// graalvm native 相关配置
graalvmNative {
	agent {
    	// 设置代理模式
		defaultMode = "conditional"
		modes {
    		// 引入 conditional 的过滤文件配置
			conditional  {
				userCodeFilterPath = "metadata-user-code-filter.json"
				extraFilterPath = "metadata-extra-filter.json"
			}
			// conditional 使用不了 access-filter 和 caller-filter 具体自己可以创建 demo 
		}
        metadataCopy {
            mergeWithExisting = true
            inputTaskNames.add("test")
            outputDirectories.add("src/test/resources/META-INF/native-image/com.alibaba.nacos/nacos-jni")
        }
    }
    metadataRepository {
        enabled = true
    }
	// 指定运行参数 如果在 main 中使用 main {} test 使用 test {}
	binaries {
		test {
			buildArgs("--enable-url-protocols=http")
        }
    }
}

test {
	useJUnitPlatform()
}

生成元数据

生成元数据

./gradlew -Pagent clean test

使用如下命令导出元数据文件

./gradlew metadataCopy --task test

清理单元测试

./gradlew clean nativeTest

在生成单元测试的过程中,可能存在生成不完全的情况。当然也可以在maven中生成相关元数据,只要手动删除一些无关的json条目就可以了。最终的结果是能够通过native build tools的nativetest即可。

如果需要一个项目的metadata,就应该为此项目编写单元测试,用单元测试生成最初版本的metadata的json文件。最后手动根据nativetest的error log或warn log对(有些缺少的json条目会表现为nativetest出现死锁)改改json文件的条目

配置文件中 配置项说明

reflect-config.json

{
  "name":"com.alibaba.nacos.api.naming.ability.ClientNamingAbility",
  "allDeclaredFields":true,
  "queryAllDeclaredMethods":true,
  "queryAllDeclaredConstructors":true,
  "methods":[
    {"name":"isSupportDeltaPush","parameterTypes":[] }, 
    {"name":"isSupportRemoteMetric","parameterTypes":[] }
  ]
},

proxy-config.json

 {
    "interfaces":["io.seata.config.Configuration"]
  },

提交元数据到中央仓库

gradle 提交元数据步骤参考:https://github.com/oracle/graalvm-reachability-metadata/blob/master/CONTRIBUTING.md

以提交 nacos 元数据为例演示!

  1. clone 元数据中央仓库到本地

    git clone https://github.com/oracle/graalvm-reachability-metadata.git
    
  2. 执行如下命令

    ./gradlew scaffold --coordinates com.alibaba:nacos-client:2.2.1
    
  3. 填充对应测试类和元数据文件

    填充单元测试时,注意需要修改如下内容

    plugins {
        id 'java'
        id 'org.graalvm.buildtools.native' version '0.9.22'
    }
    
    修改为:
    
    plugins {
        id "org.graalvm.internal.tck"
    }
    
  4. 填充完成之后,执行如下命令进行测试

    注意:去 linux 环境测试!!!相关 issue 描述:https://github.com/oracle/graalvm-reachability-metadata/issues/24

    ./gradlew test -Pcoordinates=com.alibaba:nacos-client:2.2.1
    
  5. 确认测试通过之后,说明针对已有的单元测试,没有缺少的metadata。提交 pr 到中央仓库

    nacos-client: https://github.com/oracle/graalvm-reachability-metadata/pull/325
    
  6. 如果使用到了 docker ,需要创建额外的 required-docker-images.txt 文件,之后需要提交镜像配置到中央仓库的 https://github.com/oracle/graalvm-reachability-metadata/blob/master/tests/tck-build-logic/src/main/resources/AllowedDockerImages.txt中, 不然 github ci 不通过。

    https://github.com/oracle/graalvm-reachability-metadata/pull/321
    
  7. 如果使用虚拟机测试,注意虚拟机网络连接配置

  8. 测试通过示例:
    在这里插入图片描述

值得一提的是,graalvm 不怎么 review 外部 pr,除非你主动催!!Oracle Labs 是经典的四天工作制,周五,周六,周日基本找不到人的!

linux 测试环境搭建步骤:(环境搭建,特别是安装jdk,非常慢~~~~)

cd /tmp
sudo apt install unzip zip curl sed -y
curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install java 22.3.1.r17-grl
sdk use java 22.3.1.r17-grl
gu install native-image
sudo apt-get install build-essential libz-dev zlib1g-dev -y

sdk install gradle

踩坑记录

  1. 到目前为止,graalvm 提供的获取元数据方式任然存在有不包含指定类和缺少类的情况出现,需要手动补充,可参见 pr: https://github.com/oracle/graalvm-reachability-metadata/pull/167。优化此插件体验一直是 graalvm 讨论的问题之一。

  2. gradle 错误:

     [java.net.MalformedURLException: Accessing an URL protocol that was not enabled. The URL protocol http is
     supported but not enabled by default. It must be enabled by adding the --enable-url-protocols=http option to the native-image command.]
    

需要加入相关配置:(作用给test文件夹的就是test buildargs,作用给main文件夹的就是main buildargs,在binary不同子级下)

   graalvmNative {
   	agent {
   		defaultMode = "conditional"
   		modes {
   			conditional {
   				userCodeFilterPath = "metadata-user-code-filter.json"
   				extraFilterPath = "metadata-extra-filter.json"
   			}
   		}
   	}
   	binaries {
   		test {
   			buildArgs("--enable-url-protocols=http")
           }   
       }   
   }

相关URL参考地址

Graalvm Slack:https://app.slack.com/client/TN37RDLPK/CNBFR78F9

Graalvm 元数据中央仓库:https://github.com/oracle/graalvm-reachability-metadata

nbt 插件地址:https://github.com/graalvm/native-build-tools

graalvm blog:https://easyj.icu/blog/#/native-image/theory-practice

致谢

感谢 Apache ShardingSphere 社区 commiter 泠恒谦 的指导

感谢 Seata 社区 commiter 王良 的 graalvm 相关知识介绍

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/690696.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

部署 LAMP平台Linux,Apache,MySQL ,PHP源码编译安装

目录 一、.LAMP简介与概述 1.LAMP平台概述 2. 构建LAMP平台顺序 3. 编译安装的优点 4. 各组件作用 5. 数据流向 二、编译安装Apache httpd服务 1.关闭防火墙&#xff0c;将安装Apache所需软件包传到/opt目录下 2.安装环境依赖包 3.配置软件模块 4.编译及安装 5.优…

chatgpt赋能python:Python获取父类:探究继承关系的技巧

Python获取父类&#xff1a;探究继承关系的技巧 Python是一种高级编程语言&#xff0c;它被广泛用于Web开发、数据分析、人工智能等领域。Python的面向对象编程是其特色之一。在面向对象编程中&#xff0c;我们经常需要使用继承关系来定义不同类之间的关系。在这篇文章中&…

小程序学习(一):基本知识点笔记

1.小程序与普通网页开发的区别 1.运行环境不同 网页运行在浏览器环境中 小程序运行在微信环境中 2.API不同 由于运行环境的不同,小程序无法调用DOM和BOM的API。 但是,小程序中可以调用微信环境提供的各种API,例如:地理定位、扫码、支付... 3.开发模式不同 网页的开发模式:浏览器…

C语言笔记-4 输入输出

目录 输入输出简单举例scanf()getchar()putchar()puts()gets() 标准文件%d 格式化输出整数%f 格式化输出浮点型数据 getchar() & putchar() 函数gets() & puts() 函数scanf() 和 printf() 函数 输入输出 简单举例 scanf() 空格、回车也是字符&#xff0c;下面情况也…

APP盲盒系统开发前端后台详细功能讲解

一、栏目 功能 说明 登录注册 注册 输入手j号&#xff0c;获取验zm&#xff0c;输入密m 密码登录 手机号密码 忘记密码 输入手j号&#xff0c;获取y证m&#xff0c;输入新m码 底部导航 开盲盒、寄售中心、商城、个人中心 开盲盒 显示盲盒 可滑动更换其他盲盒 立即开盒 点…

从程序员到架构师——数据持久化层场景

全文摘自&#xff1a;从程序员到架构师&#xff08;王伟杰著&#xff09; 购买链接&#xff1a;https://item.jd.com/13626926.html 程序员之间的能力差异在哪里&#xff1f;如果是学技术&#xff0c;大家可以阅读同样的书籍和网络文章&#xff0c;为什么还会造成最终专业能力的…

SC7515运算放大器(OPA)可pin对pin兼容AD8138

对于一般运算放大器&#xff0c;SC7515 在差分信号处理方面获得了巨大进步。SC7515 即可以用作单端至差分放大器或也可以差分至差分放大器&#xff0c;像运算放大器一样易于使用&#xff0c;并且大大简化了差分信号放大与驱动。可pin对pin兼容AD8138。该放大器输入噪声低、-3 d…

Spring之BeanFactory与ApplicationContext区别、实例化Bean的三种⽅式、延迟加载(lazy-Init )

Spring IoC进阶 IOC之BeanFactory与ApplicationContext区别启动 IoC 容器的方式 实例化Bean的三种⽅式使用无参构造方法实例化工厂静态方法实例化工厂实例方法实例化 Spring IOC之延迟加载(lazy-Init )Bean的延迟加载&#xff08;延迟创建&#xff09;应用场景 IOC之BeanFactor…

案例分享|梅雨季的机房湿度问题如何解决?

6月底&#xff0c;和Q3的KPI一起赶来的是南方的梅雨季。 持续不断的降雨&#xff0c;使空气湿度一度高达75%-80%&#xff0c; 南方人正式开启高温酷暑下的桑拿模式。 高温高湿除了带来体感不适&#xff0c;还会导致心情抑郁、烦燥、易疲倦...... 毕竟&#xff0c;与此强相关…

Sentinel spring的全局异常处理器,导致熔断规则(异常数规则)失效解决方案

最近在使用sentinel过程中发现&#xff0c;如果使用springboot的RestControllerAdvice全局异常捕获&#xff0c;那么设置sentinel的异常数熔断规则就会失效&#xff0c;去github上看sentinel的Issues发现已经有人提过这问题&#xff0c;官方也是没有正面回复 官方文档更不用说&…

matlab之table Excel对大量数据的缺失

Excel表格对于数据量的限制 ####### matlab之table table好处&#xff0c;可完整保留导入数据&#xff0c;不限于数值 matlab中table的切片等操作

C/C++编程安全标准GJB-8114解读——声明定义类

软件检测实验室在建立软件测试体系或申请cnas/cma相关资质时&#xff0c;需要依据相关标准&#xff0c;使用有效的方法开展检验检测活动&#xff0c;GJB-8114是一部嵌入式软件安全测试相关的国家标准&#xff0c;本系列文章我们就针对GJB-8114《C/C语言编程安全子集》的具体内容…

js逆向-md5加密算法逆向-案例网站

今天逆向的网站&#xff1a;aHR0cHM6Ly9mYW55aS55b3VkYW8uY29tL2luZGV4Lmh0bWwjLw &#xff08;去在线网站进行base64解密即可&#xff09; 1、点击翻译&#xff0c;触发请求 可以看到sign参数加密&#xff0c;加密长度为32为 md5加密特征&#xff1a; **长度固定。**无论输…

基于树莓派4B的YOLOv5-Lite目标检测的移植与部署(含训练教程)

前言&#xff1a;本文为手把手教学树莓派4B项目——YOLOv5-Lite目标检测&#xff0c;本次项目采用树莓派4B&#xff08;Cortex-A72&#xff09;作为核心 CPU 进行部署。该篇博客算是深度学习理论的初步实战&#xff0c;选择的网络模型为 YOLOv5 模型的变种 YOLOv5-Lite 模型。Y…

记一次解决vmware安装windows server 2019时, 虚拟机网络电缆被拔出,连不上网的问题

项目场景&#xff1a; 项目需要基于electron开发桌面端软件&#xff0c;实现前后端项目的自动化部署、可视化配置等功能&#xff0c;经过需求分析后&#xff0c;确定首先要适配的场景即&#xff1a;通过桌面端软件远程连接&#xff0c;在桌面端软件中执行安装、运行、配置等一…

用ZLmediaKit流媒体服务器时候遇到的常规问题

照zlmediakit的源码 自己复制了一份 然后有的地方编译不过修改了部分 测试的时候发现有两个问题 第一是 ffmpeg的ffplay 能播放 vlc不能播放 第二个问题是directProxy设置为0的时候 推流的时候 然后用ffplay播放 只有音频没有视频 查了好久终于解决这个问题 第一个…

Verilog/C++实现排序算法

Verilog/C实现排序算法 1、冒泡排序算法 冒泡排序是一种简单的交换类排序。 冒泡排序算法的原理如下&#xff1a; 1、比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。2、对每一对相邻元素做同样的工作&#xff0c;从开始第一对到结尾的最后一对。在这一…

深入解析Spring Boot:构建现代化Java应用程序的利器

深入解析Spring Boot&#xff1a;构建现代化Java应用程序的利器 文章目录 导言1. 简化的开发流程2. 内嵌的Web服务器3. 自动配置4. 健康检查和监控5. 外部化配置6. 强大的生态系统小结 导言 Spring Boot 是一个开源的Java框架&#xff0c;旨在简化和加速Java应用程序的开发过程…

关于CSPM国标证书(项目管理专业人员能力评价)

先来回答一下粉丝提问&#xff1a; 1、软考高项可以对标吗&#xff1f; 答案&#xff1a;软考高项是不可以对标的。 2、Prince2可以对应哪一个级别&#xff1f; 答案&#xff1a;哪一个级别都不可以对标&#xff0c;目前可对标的是PMI&#xff0c;IPMA、HCSE-PM&#xff08;华…

代码随想录二刷day35 |贪心 之 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球

day35 860.柠檬水找零406.根据身高重建队列452. 用最少数量的箭引爆气球 860.柠檬水找零 题目链接 解题思路&#xff1a; 局部最优&#xff1a;遇到账单20&#xff0c;优先消耗美元10&#xff0c;完成本次找零。全局最优&#xff1a;完成全部账单的找零。 代码如下&#xff1a…