从Grails应用程序使用JNI本机库时出现UnsatisfiedLinkError [英] UnsatisfiedLinkError when using a JNI native library from Grails application
问题描述
我有一个应用程序需要使用本地库: libfoo.so
我的代码是如下所示:
Accessor.java:
public class Accessor {
static {
String path =/usr/lib/libfoo.so;
System.load(path);
}
...
}
当我在独立的tomcat服务器上部署我的war文件时。
问题在于当我运行嵌入式tomcat服务器时:
grails run-app
我收到一个UnsatisfiedLinkError:
引起UnsatisfiedLinkError:com.foo.bar.GFS_MALJNI.new_Accessor__SWIG_0(Ljava / lang / String; I )J
- >> 39 | < INIT>在com.foo.bar.Accessor
中有趣的是,如果我将 BuildConfig.groovy
文件转换为fork模式,它也可以工作。
BuildConfig.groovy:
grails.project.fork = [
run:[maxMemory:1024,minMemory:64,debug:false,maxPerm:256]
]
我不想在fork模式下运行它。
我注意到正在使用两个不同的类加载器。
模式下,正在使用这个类加载器: java.net.URLClassLoader
在分叉模式下,正被使用: groovy.lang.GroovyClassLoader
原生库在分叉模式下正常工作,所以我需要来创建一个hack来以非分叉模式加载GroovyClassLoader的库。
这就是在JDK S中定义System.load的方式ource:
System.java:
public final class System {
...
public static void load(String filename){
Runtime.getRuntime()。load0(getCallerClass(),文件名);
}
...
}
调用 load0
与类加载器和文件名。显而易见的解决方案是使用自己的类加载器调用 load0
,但由于它是受封装保护的,因此无法调用它。
在groovy中编写代码时,您可以访问受打包保护的私有方法/变量。
我可以指定自己的类加载器并加载库,如下所示:
class Accessor {
static {
String path =/usr/lib/libfoo.so
//System.load(path);
Runtime.getRuntime()。load0(groovy.lang.GroovyClassLoader.class,path)
}
...
}
我只是试过了,它在非分叉模式下工作。
I have an application where I need to use a Native Library: libfoo.so
My code is as follows:
Accessor.java:
public class Accessor {
static {
String path = "/usr/lib/libfoo.so";
System.load(path);
}
...
}
This works perfectly fine when I deploy my war file in a standalone tomcat server.
The problem is when I try to run the embedded tomcat server when you run:
grails run-app
I get an UnsatisfiedLinkError:
Caused by UnsatisfiedLinkError: com.foo.bar.GFS_MALJNI.new_Accessor__SWIG_0(Ljava/lang/String;I)J
->> 39 | <init> in com.foo.bar.Accessor
Interestingly enough, if I change my BuildConfig.groovy
file to fork mode, it also works.
BuildConfig.groovy:
grails.project.fork = [
run: [maxMemory:1024, minMemory:64, debug:false, maxPerm:256]
]
I do not want to run it in fork mode.
I noticed that two different class loaders are being used.
In the non-forked mode, this class loader was being used: java.net.URLClassLoader
In the forked mode, this class loader was being used: groovy.lang.GroovyClassLoader
The native library works correctly in the forked mode, so I needed to come up with a hack to load the library with the GroovyClassLoader in the non-forked mode.
This is how System.load is defined in the JDK Source:
System.java:
public final class System {
...
public static void load(String filename) {
Runtime.getRuntime().load0(getCallerClass(), filename);
}
...
}
It's calling load0
with the classloader and filename. The obvious solution is to call load0
with your own classloader, but you can't call it since it is package-protected.
When you write code in groovy, you have access to packge-protected and private methods/variables.
I can specify my own classloader and load the library, as such:
class Accessor {
static {
String path = "/usr/lib/libfoo.so"
//System.load(path);
Runtime.getRuntime().load0(groovy.lang.GroovyClassLoader.class, path)
}
...
}
I just tried it, and it's working in non-forked mode.
这篇关于从Grails应用程序使用JNI本机库时出现UnsatisfiedLinkError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!