java.lang.UnsatisfiedLinkError:Native Library XXX.so已经加载到另一个类加载器中

Bhu*_*han 15 java java-native-interface tomcat opencv

我已经部署了一个Web应用程序,其中包含以下代码.

System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
Run Code Online (Sandbox Code Playgroud)

现在,我部署了另一个也具有相同代码的Web应用程序.当它尝试加载库时,它会抛出以下错误.

Exception in thread "Thread-143" java.lang.UnsatisfiedLinkError: 
Native Library /usr/lib/jni/libopencv_java248.so already loaded in
another classloader
Run Code Online (Sandbox Code Playgroud)

我想同时运行这两个应用程序.

直到现在我尝试过:

  1. 在一个应用程序中加载库并将上述异常捕获到另一个应用程序
  2. 从两个应用程序中删除了jar并将opencv.jar放入Tomcat的类路径中(即在/ usr/share/tomcat7/lib中).

但上面没有一个工作,我可以做任何建议吗?

编辑:对于选项二,

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Run Code Online (Sandbox Code Playgroud)

这条线有效,但在我实际使用该库时会出现异常.那是我关注的时候

Mat mat = Highgui.imread("/tmp/abc.png");
Run Code Online (Sandbox Code Playgroud)

我得到了这个例外

java.lang.UnsatisfiedLinkError: org.opencv.highgui.Highgui.imread_1(Ljava/lang/String;)J
    at org.opencv.highgui.Highgui.imread_1(Native Method)
    at org.opencv.highgui.Highgui.imread(Highgui.java:362)
Run Code Online (Sandbox Code Playgroud)

use*_*253 13

问题在于OpenCV如何处理本机库的初始化.

通常,使用本机库的类将具有加载库的静态初始化程序.这样,类和本机库将始终加载到同一个类加载器中.使用OpenCV,应用程序代码加载本机库.

现在存在一个限制,即本机库只能在一个类加载器中加载.Web应用程序使用自己的类加载器,因此如果一个Web应用程序加载了本机库,则另一个Web应用程序不能执行相同操作.因此,加载本机库的代码不能放在webapp目录中,但必须放在容器的(Tomcat)共享目录中.如果你有一个用上面常用模式编写的类(loadLibrary在使用类的静态初始化程序中),那么将包含该类的jar放在共享目录中就足够了.loadLibrary但是,使用OpenCV和Web应用程序代码中的调用,本机库仍将加载到"错误的"类加载器中,您将获得UnsatisfiedLinkError.

为了使"正确的"类加载器加载本机库,您可以使用单个静态方法创建一个小类,仅执行loadLibrary.将此类放在一个额外的jar中,并将此jar放在共享的Tomcat目录中.然后在Web应用程序中,将调用替换System.loadLibrary为对新静态方法的调用.这样,OpenCV类的类加载器及其本机库将匹配,并且可以初始化本机方法.

编辑:评论者要求的示例

代替

public class WebApplicationClass {
    static {
        System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用

public class ToolClassInSeparateJarInSharedDirectory {
    public static void loadNativeLibrary() {
        System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
    }
}

public class WebApplicationClass {
    static {
        ToolClassInSeparateJarInSharedDirectory.loadNativeLibrary();
    }
}
Run Code Online (Sandbox Code Playgroud)