Skip to content

linux-china/rust-jni-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust JNI Demo

使用Rust编写Java JNI库,Java已经非常🐂啦,为何还要用Rust来写一些代码?

  • WebAssembly支持方面Java还有一些问题,通过Rust可能更方便一些
  • Java还是不能访问一些底层的API,如SIMD,通过Rust性能提升可能非常明显
  • Rust也有非常强大的crates库 https://crates.io/ 自行选择
  • JEP 389: Foreign Linker API: https://openjdk.java.net/jeps/389

如何生成Rust JNI函数钩子

在Rust的lib.rs文件中,我们要实现JNI函数,那么这个函数的声明样式什么样的? 如函数名、签名等。

  • 首先我们根据Java类的 static native 函数生成对应的".h"文件,如下:
$ javac -h . src/main/java/org/mvnsearch/RustService.java
  • 在生成对应的".h"文件中,找到对应的声明函数,如:
JNIEXPORT jstring JNICALL Java_org_mvnsearch_RustService_hello
  (JNIEnv *, jclass, jstring);
  • 接下来在lib.rs添加对应的声明函数,然后实现其逻辑即可。
pub extern "system" fn Java_org_mvnsearch_RustService_hello(env: JNIEnv,
                                                            _class: JClass,
                                                            name: JString)
                                                            -> jstring {

考虑到时间测试的需要,个人建议是编写另外一个完全Rust Native的函数声明,然后Rust JNI函数钩子调用Rust Native函数,其目的主要是方便单元测试,如下:

fn hello(name: &str) -> String {
    format!("Hello {}!", name)
}

使用cross编译多平台的动态链接库

请参考mylib目录下的cross.sh脚本。

动态链接库加载目录

Java的System.load会从指定的目录加载,默认目录列表为System.getProperty("java.library.path"),你可以使用jshell查询,如下:

$ jshell
jshell> System.getProperty("java.library.path")
$1 ==> "~/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:."
jshell> /exit

然后将rust对应的开发包拷贝到上述之一目录就可以,如在我Mac笔记本下,命令如下:

$ cp -rf mylib/target/debug/libmylib.dylib ~/Library/Java/Extensions/

在测试的时候,我们可以通过设置java.library.path属性进行调整,只要指向Rust library的debug目录就可以,如下:

-Djava.library.path=/Users/xxxx/rust-jni-demo/mylib/target/debug

在IDE工具中,都有对应的VM options方便你进行设置。

Exception throw from Rust

fn java_string_with_exception(result: Result<String, ErrorMessages>, env: &JNIEnv) -> jstring {
    if let Ok(text) = result {
        env.new_string(text)
            .expect("Couldn't create java string!")
            .into_raw()
    } else {
        env.throw_new("java/lang/Exception", "something bad happened").unwrap();
        std::ptr::null_mut() as jstring
    }
}

References

About

Rust JNI demo for Java

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published