一文解秘Rust如何与Java互操作

在这里插入图片描述

本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0许可协议。转载请注明来自 唯你

使用场景

JAVA 与 Rust 互操作让 Rust 可以背靠 Java 大生态来做更多事情,而 Java 也可以享受 Rust 语言特性的内存安全,所有权机制,无畏并发。

互操作的典型场景包括:

  • 性能优化:利用 Rust 处理计算密集型任务,提高 Java 应用的整体性能。
  • 系统级编程:结合 Rust 的底层控制能力与 Java 的高级抽象,实现更高效的系统交互。
  • 跨平台开发:使用 Rust 编写核心逻辑,通过 JNI 在不同平台上与 Java 交互,实现高效跨平台开发。
  • 安全关键应用:在金融、医疗等领域,利用 Rust 处理敏感数据和核心功能,保证高度安全性。
  • 实时系统:在游戏引擎、音频处理等延迟敏感的应用中,使用 Rust 处理时间关键部分。

背景知识

JNI

image.png

  • 全称 Java Native Interface,它允许 Java 代码与其他语言(如 C 或 C++)编写的应用程序进行互操作。
  • JNI Specification:这是 JNI 的官方规范,详细描述了 JNI 的使用方法、接口和功能。

Java 虚拟机(JVM)

image 1.png

JNI 是 Java 虚拟机的一部分,JVM 在启动时为每个线程创建一个 JNI 环境。JNI 环境包括指向 JVM 内部数据结构的指针,这些数据结构用于存储 Java 对象、方法和字段的信息。

JNIEnv (JNI 环境)

image 2.png

  • JNIEnv是一个指向结构体的指针,代表当前线程的 JNI 环境。它包含所有 JNI 相关函数的指针,让你能在本地代码中使用这些函数。每个线程都有自己独立的JNIEnv,所以不能在不同线程间传递这个指针。
  • 可以将JNIEnv视为一个"翻译器"。当 Rust 代码需要与 Java 交互时,它通过这个"翻译器"发送请求,当调用 Java 方法或获取 Java 对象的属性。每个线程都拥有自己独立的"翻译器",这确保了各线程与 Java 交互时的独立性。

另外

  • 当 Java 代码调用本地方法时,JVM 会加载相应的本地库并创建一个JNIEnv指针。
  • 本地代码可以使用这个指针访问 JNI 提供的函数,进行 Java 对象的操作。
  • 每个线程有独立JNIEnv,保证线程安全。新线程需调用AttachCurrentThread获取对应JNIEnv
  • JNI 提供了数据类型转换机制,实现 Java 与 C/C++之间的数据传递。

在 Rust 生态中使用 jni 0.21.1 库可以实现与 Java 代码的交互。

JNI 0.21.1 简介

该项目为 Rust 提供了完整的 JNI 绑定,允许:

  • 使用 Rust 代码与 Java 库进行交互,调用 Java 方法和访问 Java 对象。

  • 从 Rust 代码中使用 Java 类和接口。

  • 实现跨语言的高效数据交换。

  • 利用 Rust 的性能优势和 Java 的成熟生态系统

跨平台 UI 框架 Flutter 源码中的 MethodChannel 实现了 Dart 与 Android 层的通信,其底层 C++也是通过 JNI 调用插件中的 onMethodCall 来实现的。这与上述 jni 0.21.1 采用了相同的思路,但存在以下不同点:

  • 语言特性和类型安全:
    Rust 的jni库提供了一种更安全的方式来处理 Java 对象和方法调用。它利用 Rust 的所有权系统来减少潜在的内存错误,使得在 Rust 中使用 JNI 时更易于管理资源和避免常见错误。
  • 多平台支持:jni 0.21.1 提供了更广泛的跨平台支持。

如何运行示例

示例源码请阅读原文,见原文底部源码获取

在 Windows 11 环境下运行示例时,笔者遇到了两个问题:

  1. Windows 自带的 PowerShell 无法直接执行 Makefile
  2. 由于 Rust 配置了特定目标平台,出现了不明原因的编译错误

以下是解决这些问题的方法:

在 MinGW-w64 中执行 Makefile

  1. 确保已在 MinGW-w64 环境中安装 mingw32-make 工具(通常随 MinGW-w64 一起安装)
  2. 打开 MinGW-w64 命令行
  3. 导航至 Makefile 所在目录
  4. 执行以下命令
//当前示例中是makefile,直接执行mingw32-make -f makefile即可
mingw32-make -f YourMakefileName

确认当前 Rust 环境

举例来说,笔者在 C:\Users\xxx.cargo 目录下配置了 config.toml 文件:

[build]
target = "aarch64-linux-android"

这导致在 Windows 上使用 mingw32-make 来编译针对 Android 平台的 Rust .so 文件,造成了混乱并引发了莫名其妙的编译错误。解决方法是删除不必要的 config.toml 文件,确保当前运行环境与目标平台(如 Windows)一致。

输出结果:

Hello, josh!
[B@2f92e0f4
factCallback: res = 720
counterCallback: count = 1
counterCallback: count = 2
counterCallback: count = 3
counterCallback: count = 4
counterCallback: count = 5
Invoking asyncComputation (thread id = 1)
asyncCallback: thread id = 23, progress = 0%
asyncCallback: thread id = 23, progress = 10%
asyncCallback: thread id = 23, progress = 20%
asyncCallback: thread id = 23, progress = 30%
asyncCallback: thread id = 23, progress = 40%
asyncCallback: thread id = 23, progress = 50%
asyncCallback: thread id = 23, progress = 60%
asyncCallback: thread id = 23, progress = 70%
asyncCallback: thread id = 23, progress = 80%
asyncCallback: thread id = 23, progress = 90%
asyncCallback: thread id = 23, progress = 100%

示例简析

让我们深入分析示例中 asyncComputation 的流程。其核心目的是在 Rust 端执行一个异步计算,同时 Rust 端会调用 Java 端来报告计算进度。

image.png

整体流程图说明:

  1. Java 的 main()方法调用 asyncComputation()。
  2. asyncComputation()通过 JNI 调用 Rust 的 Java_HelloWorld_asyncComputation()函数。
  3. Rust 函数创建一个新线程来执行异步计算。
  4. 在新线程中,Rust 执行计算并周期性地调用 Java 的 asyncCallback()方法报告进度。
  5. 当 Rust 完成计算后,控制权返回到 Java 的主线程。

这个过程展示了 Java 调用 Rust(步骤 1)和 Rust 回调 Java(步骤 4)的双向交互。

源码如下

image 3.png

#1 将一个 HelloWorld 类实例传递给 Rust 端,这对应下方 Rust 侧实现中 #3 处的 callback 对象

image 4.png

Rust 实现说明

  1. JNIEnv 参数:详见上述相关概念中的解释。
  2. JClass:代表调用此本地方法的 Java 类引用,主要用于访问类级别的静态方法和字段。
  3. callback:Java 中新创建的 HelloWorld 对象实例。
  4. 获取 JVM 对象:因为 env 对象不支持线程间传递和共享(仅实现了 Send),而 JVM 支持。通过 JVM 对象可在线程间传递,并最终获得 env
  5. 创建全局引用:获取 HelloWorld() 实例对象的全局引用,防止被垃圾回收。
  6. 线程安全:每个线程都有自己的 JNIEnv,确保线程安全。在新线程中需调用 AttachCurrentThread 获取对应的 JNIEnv
  7. 反向调用 Java:通过 env 反向调用 Java 代码。调用对象是新创建的 HelloWorld 实例,回调方法是其中的 asyncCallback。在 JNI 中,"(I)V" 是方法签名,描述了 Java 方法的参数和返回类型。"(I)V" 表示接受一个整数参数并返回 void 的方法。在这里,asyncCallback 方法接收一个整数(progress)作为参数,无返回值。

总结

  1. Java 与 Rust 互操作让两种语言优势互补,提高性能和安全性,适用于多种场景如性能优化、系统级编程和跨平台开发。
  2. JNI(Java Native Interface)是实现 Java 与 Rust 互操作的关键技术,允许 Java 代码与其他语言编写的应用程序进行交互。
  3. 通过示例分析,我们了解了 Java 调用 Rust 函数和 Rust 回调 Java 方法的双向交互过程,展示了两种语言之间的无缝协作。

参考链接

https://github.com/jni-rs/jni-rs

JNI APIs and Developer Guides

Leveraging Rust in our high-performance Java database

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

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

相关文章

架构零散知识点

1 数据库 1.1 数据库范式 有一个学生表,主键是学号,含有学生号、学生名、班级、班级名,违反了数据库第几范式? --非主属性不依赖于主键,不满足第二范式 有一个订单表,包含以下字段:订单ID&…

ZISUOJ 2024算法基础公选课练习一(1)

前言、 又是一年算法公选课&#xff0c;与去年不同的是今年学了一些纯C&#xff08;而不是带类的C&#xff09; 一、我的C模板 1.1 模板1 #include <bits/stdc.h> using i64 long long;int main() {std::cin.tie(nullptr)->sync_with_stdio(false);return 0; } 1…

25.停车场管理系统(基于web的Java项目)

目录 1.系统的受众说明 2.相关技术与方法 3.系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2 经济可行性 3.1.3 操作可行性 3.2 需求分析 3.2.1 系统功能描述 3.2.2 用例图分析 4. 系统设计 4.1 系统类分析 5. 系统详细设计与实现 5.1 用户登录 5.2 系统信…

string模拟实现构造+析构

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 string模拟实现构造 方案1&#xff08;初始化列表的实现&#xff09;&#xff1a; 这…

每日OJ题_牛客_小红的口罩_堆+贪心_C++_Java

目录 牛客_小红的口罩_堆贪心 题目解析 C代码 Java代码 牛客_小红的口罩_堆贪心 小红的口罩 描述&#xff1a; 疫情来了&#xff0c;小红网购了 n个口罩。众所周知&#xff0c;戴口罩是很不舒服的。小红每个口罩戴一天的初始不舒适度为 ai​。 小红有时候…

Bruno解决SSL验证问题

在测试接口的时候&#xff0c;我使用的是Bruno这个软件&#xff0c;开源离线的API测试软件。 主页是这样子的 今天在测试一个HTTPS的接口时候&#xff0c;因为这个HTTPS接口是用的是自签证书&#xff0c;所以就报错误了。 Error invoking remote method send-http-request: …

IBM股票分析:IBM的股价已经涨不动了吗?该买入还是卖出?

猛兽财经核心观点&#xff1a; &#xff08;1&#xff09;由于第三季度业绩疲弱&#xff0c;摩根士丹利已将IBM目标股价下调到了208美元。 &#xff08;2&#xff09;IBM的软件业务虽然增长了9.7%&#xff0c;但咨询和基础设施业务却还在挣扎。 &#xff08;3&#xff09;猛兽财…

【数据结构】线性表——顺序表

文章目录 一、线性表二、顺序表2.1概念及结构2.2、顺序表接口实现2.2.1、顺序表的动态存储2.2.2、顺序表初始化2.2.3、检查空间判断进行增容2.2.4、顺序表尾插、尾删2.2.5、顺序表头插、头删2.2.6、顺序表查找2.2.7、顺序表在pos位置插入x2.2.8、顺序表删除pos位置的值2.2.9、顺…

JAVA基础:分页 (学习笔记)【DVD分页查看】

分页 分页一张表---创建entry类 分页多张表---创建pojo类 1&#xff0c;准备实体类 com.jr.entry.DVD 2&#xff0c;接口问题&#xff1a; &#xff08;1&#xff09;根据条件 --- 获得符合条件的总条数 &#xff08;2&#xff09;根据条件 --- 获得符合条件的集合数据。 …

macOS开发环境配置与应用开发(详细讲解)

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 1. 引言 macOS作为Apple公司推出的桌面操作系统&#xff0c;以其稳定性、优雅的用户界面和强大的开发工具吸引了大量开发者。对于…

Qt桌面应用开发 第二天(信号和槽 Lambda表达式)

目录 1.信号和槽 1.1信号 1.2信号和槽重载问题 1.3 注意事项 1.4信号和槽Lambda表达式 1.信号和槽 信号的发送者——信号——信号的接受者——信号的处理&#xff08;槽函数&#xff09; connect(信号的发送者&#xff0c;发送的信号&#xff0c;信号的接受者&#xff0…

ubuntu 22.04 server 安装 anaconda3

ubuntu 22.04 server 安装 anaconda3 https://www.anaconda.com/download/success Anaconda Installers wget https://repo.anaconda.com/archive/Anaconda3-2024.10-1-Linux-x86_64.sh 其他的是 默认 Executing transaction: done installation finished. Do you wish to…

如何设置VSCODE快捷键光标移到行首和行尾

{ "key": "cmdhome", "command": "cursorTop", },{ "key": "cmdend", "command": "cursorBottom", }

台新金控在台北金融科技展上展示自研GenAI应用与LLM

在今年的台北金融科技展上&#xff0c;多家金融机构展示了他们的生成式人工智能&#xff08;GenAI&#xff09;应用。其中&#xff0c;台新金控也展示了包括升级后的智能客服、面向企业金融客户的拟真客服人员、影片生成服务以及音乐生成服务等应用。 然而&#xff0c;台新的亮…

项目开发流程规范文档

项目开发流程规范文档 目标: 明确项目组中需求管理人员, 交互设计, 美工以及开发之间的工作输入输出产物. 明确各岗位职责. 以免造成开发, 产品经理以及项目经理之间理解不到位, 沟通成本过高,返工造成资源浪费. 所有环节产生的文档都可以作为项目交付的资源. 而不是事后再补文…

Go API 多种响应的规范化处理和简化策略

一个对外提供API接口的服务&#xff0c;在真正动工开发接口前一般需要先确定一下接口响应的通用格式&#xff0c;无论接口响应里返不返回业务数据&#xff0c;返回的数据是字符串、列表、对象还是其他类型都会遵照这个通用的响应格式。 既然一个项目接口的响应格式是确定的&…

poi excel数据统计导出

##poi excel导出案例 1.ajxa导出请求没有任何反应&#xff0c;打断点看了workBook中也有数据&#xff0c;网上查阅说ajax请求导出无法接收流&#xff0c;换成location.href,果然可以了 2.控制器代码 response.setCharacterEncoding("UTF-8");response.setContentTyp…

基于Python的影院电影购票系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

SQL Server 多数据源配置

目录 1、添加依赖 2. 配置数据源 3. 创建数据源配置类 4. 创建Mapper接口和XML映射文件 5. 使用Mapper 6.启动类配置 7.项目结构目录 1、添加依赖 首先&#xff0c;在pom.xml文件中添加SQL Server的JDBC驱动&#xff1a; <!-- SQL Server Connector --> <dep…

FlinkSql读取外部Mysql和HBase数据库的方法(scala)

我的Flink版本为1.13.6 <flink.version>1.13.6</flink.version> FlinkSql读取外部的MySQL是走的JDBC所以需要以下两个依赖&#xff1a; <dependency><groupId>org.apache.flink</groupId><artifactId>flink-connector-jdbc_${scala.bina…