使用Grails应用程序中的JNI本机库时出现UnsatisfiedLinkError

时间:2013-05-22 14:51:34

标签: java grails java-native-interface swig unsatisfiedlinkerror

我有一个应用程序需要使用本机库: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模式下运行它。

2 个答案:

答案 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中运行)。通过将调试语句添加到静态块来测试它。