使用Grails应用程序中的JNI本机库时出现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 |  in 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

本机库在分叉模式下正常工作,因此我需要在非分叉模式下使用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保护的和私有的方法/变量。

我可以指定自己的类加载器并加载库,如下所示:

 class Accessor { static { String path = "/usr/lib/libfoo.so" //System.load(path); Runtime.getRuntime().load0(groovy.lang.GroovyClassLoader.class, path) } ... } 

我刚尝试过它,它在非分叉模式下工作。

我的猜测是,Accessor类在同一个JVM中的不同类加载器中被多次加载(假设grails在与嵌入式Tomcat相同的JVM中运行)。 通过将调试语句添加到静态块来测试它。