我有一个应用程序需要使用本机库:libfoo.so
我的代码如下:
Accessor.java:
public class Accessor {
static {
String path = "/usr/lib/libfoo.so";
System.load(path);
}
...
}
当我在独立的tomcat服务器中部署war文件时,这非常正常。
问题是当我在运行时尝试运行嵌入式tomcat服务器时:
grails run-app
我得到一个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
有趣的是,如果我将BuildConfig.groovy
文件更改为fork模式,它也可以工作。
BuildConfig.groovy:
grails.project.fork = [
run: [maxMemory:1024, minMemory:64, debug:false, maxPerm:256]
]
我不想在fork模式下运行它。
答案 0 :(得分:3)
我注意到正在使用两个不同的类加载器。
在非分叉模式下,正在使用此类加载器:java.net.URLClassLoader
在分叉模式下,正在使用此类加载器:groovy.lang.GroovyClassLoader
本机库在分叉模式下正常工作,所以我需要在非分叉模式下使用GroovyClassLoader来加载库。
这是在JDK源中定义System.load的方式:
的 System.java:强> 的
public final class System {
...
public static void load(String filename) {
Runtime.getRuntime().load0(getCallerClass(), filename);
}
...
}
它使用类加载器和文件名调用load0
。显而易见的解决方案是使用您自己的类加载器调用load0
,但由于它受包保护,因此您无法调用它。
当你在groovy中编写代码时,你可以访问packge-protected和private方法/变量。
我可以指定自己的类加载器并加载库,如下所示:
class Accessor {
static {
String path = "/usr/lib/libfoo.so"
//System.load(path);
Runtime.getRuntime().load0(groovy.lang.GroovyClassLoader.class, path)
}
...
}
我刚试过它,它正在非分叉模式下工作。
答案 1 :(得分:0)
我的猜测是,Accessor类在同一个JVM中的不同类加载器中被多次加载(假设grails在与嵌入式Tomcat相同的JVM中运行)。通过将调试语句添加到静态块来测试它。