小编典典

java.lang.UnsatisfiedLinkError:本机库XXX.so已加载到另一个类加载器中

tomcat

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

System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);

现在,我部署了另一个具有相同代码的Web应用程序。尝试加载库时,将引发以下错误。

Exception in thread "Thread-143" java.lang.UnsatisfiedLinkError: 
Native Library /usr/lib/jni/libopencv_java248.so already loaded in
another classloader

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

直到现在我已经尝试了:

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

但是以上方法均无效,我可以通过任何建议做到这一点?

编辑: 对于选项二,

System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

这行有效,但是在我实际要使用该库时会出现异常。那是当我跟随

Mat mat = Highgui.imread("/tmp/abc.png");

我得到这个例外

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)

阅读 660

收藏
2020-06-16

共1个答案

小编典典

问题在于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);
    }
}

采用

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

public class WebApplicationClass {
    static {
        ToolClassInSeparateJarInSharedDirectory.loadNativeLibrary();
    }
}
2020-06-16