通过JNI调用System.loadLibrary()不会加载本机方法
Calling System.loadLibrary() via JNI does not load native methods
我们有一个本地C++应用程序,它创建了一个嵌入式JVM。这个JVM中的类使用SWIG包装器回调到C++对象方法中(尽管SWIG的使用并不重要;它可以很容易地是从javah生成的本机函数存根)。例如,我们有一个Java类,它有一个本地方法,如:
package net.foo;
public class CppWrapJNI {
public final static native long foo(
long l, Stuff jarg1_, String s
);
}
在C++DLL中有一个相应的实现:
extern "C" {
__declspec(dllexport) jlong JNICALL
Java_net_foo_CppWrapJNI_1foo(
JNIEnv *jenv, jclass jcls,
jlong jarg1, jobject jarg1_, jstring jarg2
) {
return 1;
}
}
假设这个DLL名为"foo.DLL"。
然后,我们尝试让JVM通过JNI加载DLL,使用如下代码:
jclass cls = env->FindClass("java/lang/System");
jmethodID mid = env->GetStaticMethodID(
cls, "loadLibrary", "(Ljava/lang/String;)V"
);
jstring jstr = env->NewStringUTF("foo.dll");
env->CallStaticVoidMethodV(cls, mid, jstr);
这一切都有效,并且对loadLibrary()的调用没有报告任何错误(这里没有显示JNI异常处理,但我们会这样做)。然而,稍后对CppWrapJNI.foo()的调用失败,并返回如下错误:
java.lang.UnsatisfiedLinkError:
net.foo.CppWrapJNI.foo(JLnet/foo/Stuff;Ljava/lang/String;)J
奇怪的是,如果我纯粹用Java编写一个测试工具,用同样的方式调用loadLibrary,一切都会正常工作。这很令人沮丧,因为我在网上读到的一切都表明这应该很好。
最后,我查看了System.loadLibrary的源代码:
@CallerSensitive
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
}
啊哈!反射.getCallerClass()是关键。没有调用者类!它来自于直接的C++。解决方案相当简单,围绕System.load*()编写一个门面,我们可以从C++调用它,它将反过来调用System方法:
public class SystemFacade {
public static void load(String path) {
java.lang.System.load(path);
}
public static void loadLibrary(String name) {
java.lang.System.loadLibrary(name);
}
}
瞧,它起作用了。据推测,任何java而不是C++通过JNI进行调用的变体也可以避免这个问题。@CallerSensitive标签似乎是一条线索;不要通过JNI呼叫这些!我希望这篇帖子能让其他人省去我所经历的挫折。我仍然困惑于为什么加载似乎成功了,但却没有找到任何符号。
相关文章:
- Java JNI GDAL 本机库在重新部署为 Web 应用程序时出现类加载器错误
- 托管语言是否锁定本机库的刷新和重新加载变量?
- 将本机非托管的C DLL加载到托管的C#应用中,导致DLL输出垃圾
- 调试Android Studio中动态加载的本机库
- Excel 2016 VSTO 加载项与本机代码 DLL
- 无法加载生成的本机库
- Android本机运行时无法加载符号,即使它们实际上是在加载的.so文件中找到的
- 纯粹的分离性:无法开始活动;无法加载本地库
- 在Visual Studio 2015中调试本机应用程序加载的托管DLL
- 通过JNI调用System.loadLibrary()不会加载本机方法
- 使用本机依赖项加载 CLR 库
- 由本机C++加载的 DLL 中的 C# 窗体
- Azure 网站是否支持 P/Invoke 来加载本机 C++ DLL
- 在客户端加载本机插件
- 无法在Android棉花糖上加载本机库,但可以在棒棒糖上使用
- nodejs如何加载本机插件
- 使用本机DLL从同一文件夹加载程序集
- 我如何让IIS加载我的WCF服务引用的本机DLL
- 在进行托管到本机的互操作时,操作系统加载器锁定
- 在64位环境中加载本机COM dll