当前位置: 首页 > news >正文

Graalvm配置文件与Feature和Substitute机制介绍

GraalVM介绍

GraalVM提前将Java应用程序编译成独立与机器码二进制文件(可执行文件、动态库文件),如windows系统中的exe文件和dll文件。与在Java虚拟机(JVM)上运行的应用程序相比,这些二进制文件更小,启动速度快100倍,在没有预热的情况下提供峰值性能,并且使用更少的内存和CPU。

下面只介绍开发中与Graalvm相关的配置文件和扩展点(Feature和Substitute机制)以及maven插件配置。

1. 配置文件

1.1 动态代码配置文件

对于动态代码,需要通过指定的json文件来描述其metadata,这样GraalVM才能正确的编译和优化代码。如下类型

  • 反射,配置文件名:reflect-config.json
  • 动态代理, 配置文件名:proxy-config.json
  • 资源文件, 配置文件名:resource-config.json
  • JNI, 配置文件名:jni-config.json,配置被JNI代码调用的java方法,可见jni-lib模块
  • 资源序列化, 配置文件名:serialization-config.json
  • predefined classes, 配置文件名:predefined-classes-config.json

这些JSON文件内容格式可见github: graalvm json file schema

1.2 命令参数配置文件

graalvm推荐开发者为自己的项目提供文件名为native-image.properties的配置文件,在该配置文件中可指定native-image编译分析所需要的配置,在properties文件中,支持如下key:

  1. Args 配置native-image命令参数,如–feature指定扩展的Feature接口、–initialize-at-build-time指定编译时初始化的类。更多命令行选项见Command-line Options
  2. JavaArgs 配置native-image执行时的JVM参数
  3. ImageName 配置最后生成的可执行文件名称

关于native-image.properties的内容更多具体的可见文档Native Image Build Configuration

1.3 存放位置

配置文件都存放在项目jar文件的META-INF/native-image/目录下,native-image会自动加载该目录下的文件。如:

META-INF/
└── native-image└── native-image.properties└── reflect-config.json└── jni-config.json

为了防止多个jar文件内的配置冲突,graalvm推荐在META-INF/native-image/目录下新建以你项目的groupId/artifactID为子目录,如:

META-INF/
└── native-image└── groupID└── artifactID└── native-image.properties└── reflect-config.json└── jni-config.json

2. 动态代码配置示例

2.1 反射

  1. 类所有方法都可以用于反射,reflect-config.json配置如下
[{"name": "com.example.User","allDeclaredConstructors": true,"allPublicMethods": true,"allDeclaredFields": true}
]
  1. 类中指定方法和字段可用于反射,配置示例如下
[{"name": "com.example.User","fields": [{"name": "name"}],"methods": [{"name": "<init>","parameterTypes": []},{"name": "setName","parameterTypes": ["java.lang.String"]}]}
]

2.2 动态代理

  1. 假设接口com.example.IPrintServic会用于动态代理,proxy-config.json配置示例如下
[{"interfaces": ["com.example.IPrintService"]}
]

2.3 资源文件

假设有如下代码用于加载类路径下的资源

try(InputStream stream = this.getClass().getClassLoader().getResourceAsStream(“resource_config.properties”)) {//读取资源内容
} 

resource-config.json配置示例如下

{"resources": {"includes": [{"pattern": "\\Qresource_config.properties\\E"}]}
}

说明: 上面pattern属性值为正则表达式,字符\Q\E之间的内容在正则表达式中表示字面量,即对其中的特殊字符进行原始匹配,比如上面的.不是匹配任意字符,而就是匹配字符串中的.

2.4 类序列化

如果项目中类com.example.User使用了JDK的序列化方式,则其serialization-config.json配置示例如下

[{"name": "com.example.User"}
]

2.5 JNI中调JAVA API

如果JNI代码中有调com.example.Utils类的public static int add(int,int)方法,则jni-config.json配置示例如下

[
{"name":"com.example.Utils","methods":[{"name":"add","parameterTypes":["int","int"] }]
}
]

3. 扩展Feature接口

native-image生成可执行代码过程中会在关键步骤执行用户自定义代码,而用户代码的执行是通过graalvm的Feature机制实现的,开发者可以实现Feature接口来为程序设置一些特定行为,比如通过编码的方式设置以上动态代码配置。

示例

示例需求: 为com.example包下注解了@Reflect注解的类注册反射配置

  1. 实现Feature接口
public class ReflectFeature implements Feature {@Overridepublic void beforeAnalysis(BeforeAnalysisAccess access) {// 注册元数据try (ScanResult graph = new ClassGraph().overrideClassLoaders(access.getApplicationClassLoader()).overrideClasspath(access.getApplicationClassPath()).enableAllInfo().acceptPackages("com.example").scan()) {graph.getClassesWithAnnotation(Reflect.class).forEach(classInfo -> {Class clazz = classInfo.loadClass();RuntimeReflection.register(clazz);RuntimeReflection.registerForReflectiveInstantiation(clazz); // 可通过newInstance()方法创建,与allDeclaredConstructors=true类似RuntimeReflection.register(clazz.getDeclaredFields()); // allDeclaredFields=true类似RuntimeReflection.register(clazz.getDeclaredMethods());// allPublicMethods=true类似});}}
}

注:以上包扫描使用classgraph工具,它与其它反射工具相比优势在于它是直接解析字节码来进行匹配的,好处就是不用把类加载到JVM中。classgraph的maven配置如下:

<dependency><groupId>io.github.classgraph</groupId><artifactId>classgraph</artifactId><version>4.8.173</version>
</dependency>
  1. 注册自定义的com.example.feature.ReflectFeature接口
    有两种方式,
    1. 方式一:在native-image命令行使用参数配置--features=com.example.feature.ReflectFeature指定
    2. 方式二:推荐在native-image.properties文件配置,内容如下
     Args = --features=com.st.graalvm.feature.StepTrackFeature
    

4. Substitute机制

Substitute替换机制使得可以在不修改源代码的前提下,对运行时行为进行适配改造,以保持对原API的兼容。 GraalVM本身也通过该机制对JDK API做了很多兼容性替换。

基于该机制,开发者也可以根据实际需求对一些类、方法、字段甚至是构造函数在native-image编译过程中进行替换。

替换通过注解来实现,native-image编译过程会扫描这些特定注解的类,替换类必须为final类型,命名格式推荐为Target_{原类包名}_{原类名}
替换机制提供的注解如下

  1. @TargetClass 注解替换类,其value值为被替换类

  2. @Substitute 注解替换方法,被注解的方法在方法名和签名上需与目标方法一致

  3. @Alias 注解在替换字段上,被注解的字段在名称和签名上需与目标字段一致,

    1. 搭配**@InjectAccessors**注解可拦截字段的get和set方法,示例如下
     @Alias @InjectAccessors(Target_OriginClass_Version_value.class)
    private static String version;
    static class Target_OriginClass_Version_value {private static String versionValue;static String getVersion() {if (versionValue == null) {versionValue = "44444444L_substitute";}return versionValue;}static void setVersion(String value) {System.out.println("setVersion:"  + value);}
    }
    
    1. 搭配**@RecomputeFieldValue**注解可替换字段的值,示例如下
    // 替换静态字段,需设置isFinal=true
    @Alias @RecomputeFieldValue(kind = Kind.FromAlias, isFinal = true)
    private static boolean useNative = true;
    // 替换字段
    @Alias @RecomputeFieldValue(kind = Kind.FromAlias)
    private boolean inited = true;
    
  4. @Inject 注解在替换类的字段上,该字段在被替换类中不存在,需搭配@RecomputeFieldValue注解,示例如下

@TargetClass(OriginClass.class)
public final class Target_com_example_OriginClass {// 替换并设置字段值@Alias @InjectAccessors(Target_OriginClass_Type_value.class)private TypeEnum type;@Inject @RecomputeFieldValue(kind = Kind.Reset)private TypeEnum typeValue;static class Target_OriginClass_Type_value {static TypeEnum getType(Target_OriginClass receiver) {if (receiver.typeValue == null) {receiver.typeValue = TypeEnum.SUBSTITUTE;}return receiver.typeValue;}static void setType(Target_OriginClass receiver, TypeEnum value) {receiver.typeValue = value;}}
}

5. maven编译打包配置

<plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><version>0.10.2</version><extensions>true</extensions><executions><execution><id>build-native</id><goals><goal>compile-no-fork</goal></goals><phase>package</phase></execution><execution><id>test-native</id><goals><goal>test</goal></goals><phase>test</phase></execution></executions><configuration><imageName>${project.artifactId}</imageName><sharedLibrary>false</sharedLibrary><metadataRepository><enabled>true</enabled></metadataRepository></configuration>
</plugin>

6. 其它特性

  1. 创建动态库供C/C++,可见文档Build a Native Shared Library
  2. JAVA代码可以直接调动态库接口,不过java代码需要经过native-image编译后才能运行
  3. 创建JNI接口,在之前JNI接口实现都是C/C++编写,使用native-image可以直接使用JAVA来编写JNI接口实现,可见文档JNI Invocation API
  4. 与其它语言集成(包含的语言有JS/Node.js、Python、R、Ruby、WebAssembly、LLVM语言),在Truffle基础上实现,可见文档Embedding Languages

工具

1. 使用native-image-agent代理库生成metadata文件

如果不清楚应用中有哪些动态代码需要提供配置,可以使用graalvm提供native-image-agent来跟踪代码执行情况来生成metadata文件,只需要在java启动参数中加上-agentlib:native-image-agent参数即可,命令示例如下

java -agentlib:native-image-agent=config-output-dir=graalvm -jar graalvm-1.0-SNAPSHOT.jar

总结

  1. Java语言的动态特性阻碍了native-image静态分析和编译,开发者需要提供相应的配置文件native-image才能完整的识别出需要静态编译的代码。
  2. Feature机制和替换机制为开发者提供了在编译期间尽可能多的控制
  3. 通过native-image不仅可以把应用编译为可执行文件,也可以把公共库编译为动态库供其它语言调用,还可以把公共库通过JNI接口暴露给其它java程序使用。

相关文章:

Graalvm配置文件与Feature和Substitute机制介绍

GraalVM介绍 GraalVM提前将Java应用程序编译成独立与机器码二进制文件&#xff08;可执行文件、动态库文件&#xff09;,如windows系统中的exe文件和dll文件。与在Java虚拟机&#xff08;JVM&#xff09;上运行的应用程序相比&#xff0c;这些二进制文件更小&#xff0c;启动速…...

Appium adb 获取appActivity

方法一&#xff08;最简单有效的方法&#xff09; 通过cmd命令&#xff0c;前提是先打开手机中你要获取包名的APP adb devices -l 获取连接设备详细信息 adb shell dumpsys activity | grep mFocusedActivity 有时获取到的不是真实的Activity 方法二 adb shell monkey -p …...

调整分区失败致盘无法访问:深度解析与数据恢复全攻略

调整分区失败盘打不开的困境 在计算机的日常维护与管理中&#xff0c;调整磁盘分区是常见的操作之一&#xff0c;旨在优化存储空间布局、提升系统性能或满足特定应用需求。然而&#xff0c;当这一操作未能如预期般顺利进行&#xff0c;反而导致分区调整失败&#xff0c;进而使…...

试用笔记之-汇通计算机等级考试软件一级Windows

首先下载汇通计算机等级考试软件一级Windows http://www.htsoft.com.cn/download/htwork.rar...

Java的NIO体系

目录 NIO1、操作系统级别下的IO模型有哪些&#xff1f;2、Java语言下的IO模型有哪些&#xff1f;3、Java的NIO应用场景&#xff1f;相比于IO的优势在哪&#xff1f;4、Java的IO、NIO、AIO 操作文件读写5、NIO的核心类 :Buffer&#xff08;缓冲区&#xff09;、Channel&#xff…...

自下而上的选股与自上而下的选股

一起学习了《战胜华尔街》&#xff0c;不知道大家有没有这么一种感受&#xff1a;林奇的选股方法是典型的自下而上的选股方法。虽然这一点没有单独拎出来讨论过&#xff0c;但在《从低迷中寻找卓越》《如何通过财务指标筛选股票&#xff1f;》《边逛街边选股&#xff1f;》《好…...

Tech Talk:智能电视eMMC存储的五问五答

智能电视作为搭载操作系统的综合影音载体&#xff0c;以稳步扩大的市场规模走入越来越多的家庭&#xff0c;成为人们生活娱乐的重要组成部分。存储部件是智能电视不可或缺的组成部分&#xff0c;用于保存操作系统、应用程序、多媒体文件和用户数据等信息。智能电视使用eMMC作为…...

scikit-learn教程

scikit-learn&#xff08;通常简称为sklearn&#xff09;是Python中最受欢迎的机器学习库之一&#xff0c;它提供了各种监督和非监督学习算法的实现。下面是一个基本的教程&#xff0c;涵盖如何使用sklearn进行数据预处理、模型训练和评估。 1. 安装和导入包 首先确保安装了…...

CentOS 7 搭建rsyslog日志服务器

CentOS 7 搭建rsyslog日志服务器 前言一、IP地址及主机名称规划1.修改主机名 二、配置rsyslog日志服务器1.安装rsyslog服务2.编辑/etc/rsyslog.conf 文件3.启动并启用rsyslog服务4.验证端口是否侦听 三、在rsyslog日志服务器上配置firewalld防火墙四、配置rsyslog日志客户端1.编…...

使用Spring Boot Actuator监控应用健康状态

使用Spring Boot Actuator监控应用健康状态 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何利用Spring Boot Actuator来监控和管理应用程序的…...

leetcode刷题:vector刷题

​ ​ &#x1f525;个人主页&#xff1a;guoguoqiang. &#x1f525;专栏&#xff1a;leetcode刷题 1.只出现一次的数字 这道题很简单&#xff0c;我们只需要遍历一次数组即可通过异或运算实现。(一个数与自身异或结果为0&#xff0c;任何数与0异或还是它本身) class Solut…...

CGI面试题及参考答案

什么是CGI?它在Web服务器与应用程序之间扮演什么角色? CGI(Common Gateway Interface) 是一种标准协议,它定义了Web服务器与运行在服务器上的外部程序(通常是脚本或应用程序)之间的通信方式。简单来说,CGI充当了一个桥梁,使得Web服务器能够将用户的请求传递给后端程序…...

论文调研_物联网漏洞检测综述

A Review of IoT Firmware Vulnerabilities and Auditing Techniques 研究背景&#xff1a;物联网设备在工业、消费类等各个领域得到了广泛应用&#xff0c;实现了更高的自动化和生产率。然而&#xff0c;这些连网设备的高度依赖也带来了一系列网络安全威胁&#xff0c;特别是…...

Java学习【IO流:深入理解与应用(上)】

Java学习【IO流&#xff1a;深入理解与应用&#xff08;上&#xff09;】 &#x1f343;1.IO流体系结构&#x1f343;2.FileOutputStream&#x1f341;2.1FileOutputStream写数据的三种方式&#x1f341;2.2换行和续写 &#x1f343;3.FileInputStream&#x1f341;3.1每次读取…...

干货系列:SpringBoot3第三方接口调用10种方式

环境&#xff1a;SpringBoot.3.3.0 1、简介 在项目中调用第三方接口是日常开发中非常常见的。调用方式的选择通常遵循公司既定的技术栈和架构规范&#xff0c;以确保项目的一致性和可维护性。无论是RESTful API调用、Feign声明式HTTP客户端、Apache HttpClient等调用方式&…...

KVM性能优化之CPU优化

1、查看kvm虚拟机vCPU的QEMU线程 ps -eLo ruser,pid,ppid,lwp,psr,args |awk /^qemu/{print $1,$2,$3,$4,$5,$6,$8} 注:vcpu是不同的线程&#xff0c;而不同的线程是跑在不同的cpu上&#xff0c;一般情况&#xff0c;虚拟机在运行时自身会点用3个cpus&#xff0c;为保证生产环…...

lua中判断2个表是否相等

当我们获取 table 长度的时候无论是使用 # 还是 table.getn 其都会在索引中断的地方停止计数&#xff0c;而导致无法正确取得 table 的长度&#xff0c;而且还会出现奇怪的现象。例如&#xff1a;t里面有3个元素&#xff0c;但是因为最后一个下表是5和4&#xff0c;却表现出不一…...

uni-app 自定义支付密码键盘

1.新建组件 payKeyboard .vue <template><view class"page-total" v-show"isShow"><view class"key-list"><view class"list" v-for"(item,index) in keyList" :class"{special:item.keyCode190…...

抖音微短剧小程序源码搭建:实现巨量广告数据高效回传

在数字化营销日益盛行的今天&#xff0c;抖音微短剧小程序已成为品牌与观众互动的新渠道。这些短小精悍的剧目不仅能迅速抓住用户的注意力&#xff0c;还能有效提升品牌的知名度和用户黏性。然而&#xff0c;想要充分利用这一营销工具&#xff0c;关键在于如何高效地追踪广告数…...

springboot数字化医院产科系统源码

目录 一、系统概述 二、开发环境 三、功能设计 四、功能介绍 一、系统概述 数字化产科是为医院产科量身定制的信息管理系统。它管理了孕妇从怀孕开始到生产结束42天一系列医院保健服务信息。该系统由门诊系统、住院系统、数据统计模块三部分组成&#xff0c;与医院HIS、LI…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

书籍“之“字形打印矩阵(8)0609

题目 给定一个矩阵matrix&#xff0c;按照"之"字形的方式打印这个矩阵&#xff0c;例如&#xff1a; 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为&#xff1a;1&#xff0c;…...

文件上传漏洞防御全攻略

要全面防范文件上传漏洞&#xff0c;需构建多层防御体系&#xff0c;结合技术验证、存储隔离与权限控制&#xff1a; &#x1f512; 一、基础防护层 前端校验&#xff08;仅辅助&#xff09; 通过JavaScript限制文件后缀名&#xff08;白名单&#xff09;和大小&#xff0c;提…...

数据库正常,但后端收不到数据原因及解决

从代码和日志来看&#xff0c;后端SQL查询确实返回了数据&#xff0c;但最终user对象却为null。这表明查询结果没有正确映射到User对象上。 在前后端分离&#xff0c;并且ai辅助开发的时候&#xff0c;很容易出现前后端变量名不一致情况&#xff0c;还不报错&#xff0c;只是单…...

Redis上篇--知识点总结

Redis上篇–解析 本文大部分知识整理自网上&#xff0c;在正文结束后都会附上参考地址。如果想要深入或者详细学习可以通过文末链接跳转学习。 1. 基本介绍 Redis 是一个开源的、高性能的 内存键值数据库&#xff0c;Redis 的键值对中的 key 就是字符串对象&#xff0c;而 val…...

k8s从入门到放弃之Pod的容器探针检测

k8s从入门到放弃之Pod的容器探针检测 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;容器探测是指kubelet对容器执行定期诊断的过程&#xff0c;以确保容器中的应用程序处于预期的状态。这些探测是保障应用健康和高可用性的重要机制。Kubernetes提供了两种种类型…...