JNI-为什么rt.jar System.load不起作用,但包装方法起作用?

问题描述

这是一个演示(我省略了utils,他们只是检查异常和打印消息):

第一次尝试,它应该可以工作:

C ++部分:

jclass jClass_java_lang_System = env->FindClass("java/lang/System");
jmethodID jMethodID_java_lang_System_load = env->GetStaticMethodID(jClass_java_lang_System,"load","(Ljava/lang/String;)V");
env->CallStaticVoidMethod(jClass_java_lang_System,jMethodID_java_lang_System_load,library_path);

没有例外,但是之后,调用本机方法导致UnsatisfiedLinkError

第二次尝试,编写一个包装方法:

public static void load(String path) {
    System.load(path);
}

并从C ++调用

jmethodID jMethodID_Driver_load = env->GetStaticMethodID(jClass_Driver,"(Ljava/lang/String;)V");
env->CallStaticVoidMethod(jClass_Driver,jMethodID_Driver_load,library_path);
checkException(env);

它只是System.load的包装器,仅此而已,工作正常。本地呼叫正常工作。

然后进行更多测试,但没有任何意义-都使用它们:

jclass jClass_java_lang_System = env->FindClass("java/lang/System");
jmethodID jMethodID_java_lang_System_load = env->GetStaticMethodID(jClass_java_lang_System,library_path);
if (!checkException(env)) std::cout << "Load by rt.jar no Exception" << std::endl;

jclass jClass_Driver = env->FindClass("Driver");
jmethodID jMethodID_Driver_load = env->GetStaticMethodID(jClass_Driver,library_path);
checkException(env); // The first UnsatisfiedLinkError print by this util

// Second UnsatisfiedLinkError print by native method call,I omit it.

得到这个结果:

Load by rt.jar no Exception
java.lang.UnsatisfiedLinkError: Native Library XXXXX already loaded in another classloader
java.lang.UnsatisfiedLinkError: XXXXXXX

这使它更加混乱,java.lang.System-load()的第一次尝试show加载不起作用,但实际上是在加载库。然后抛出一个重复的加载异常。

并颠倒顺序:

jclass jClass_Driver = env->FindClass("Driver");
jmethodID jMethodID_Driver_load = env->GetStaticMethodID(jClass_Driver,library_path);
checkException(env);

jclass jClass_java_lang_System = env->FindClass("java/lang/System");
jmethodID jMethodID_java_lang_System_load = env->GetStaticMethodID(jClass_java_lang_System,library_path);
if (!checkException(env)) std::cout << "Load by rt.jar no Exception" << std::endl;

并得到以下结果:

Load by wrapper no Exception
java.lang.UnsatisfiedLinkError: Native Library XXXX already loaded in another classloader
Result is - 2468
Result is - 2468

即使抛出重复的加载异常,本地调用也可以正常工作。

问题:会发生什么?该怎么解决?

解决方法

当您使用System.load()加载本机库时,VM会尝试将其找到的任何JNI函数绑定到其Java对应的JNI函数,即声明本机方法的类。仅当该类已加载时,它才能这样做。如果事后加载该类,则将具有未绑定的本机方法,并且在调用它们时会得到一个UnsatisfiedLinkError

要能够调用您的包装器方法,您要做加载该类,因此VM 可以绑定本机方法。要仅通过调用System.load()来实现此目的,请确保VM已具有该类。也就是说,最好使用通常的方法从类本身的静态初始化程序中加载本机库。 loadLibrary还将找到静态链接的库。因此,如果您将JNI函数与其余代码分开,然后将它们放入自己的库中,则可以静态链接它们并使用带有简单名称的loadLibrary

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...