我已经部署了一个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
我想同时运行这两个应用程序。
直到现在我已经尝试了:
但是以上方法均无效,我可以通过任何建议做到这一点?
编辑:选项二的,
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
这行有效,但是在我实际要使用该库时会出现异常。那是当我跟随
Mat mat = Highgui.imread("/tmp/abc.png");
我得到这个异常(exception)
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)
最佳答案
问题在于OpenCV如何处理 native 库的初始化。
通常,使用 native 库的类将具有加载该库的静态初始化程序。这样,类和 native 库将始终在同一类加载器中加载。使用OpenCV,应用程序代码将加载 native 库。
现在有一个限制,即只能在一个类加载器中加载 native 库。 Web应用程序使用它们自己的类加载器,因此,如果一个Web应用程序已加载 native 库,则另一个Web应用程序将无法执行相同的操作。因此,无法将加载代码的 native 库放置在webapp目录中,而必须放置在容器的(Tomcat)共享目录中。当您使用上面的常用模式编写了一个类(使用类的静态初始化器中的loadLibrary
)时,将包含该类的jar放在共享目录中就足够了。但是,使用OpenCV和Web应用程序代码中的loadLibrary
调用, native 库仍将被加载到“错误的”类加载器中,并且您将获得UnsatisfiedLinkError
。
要使“正确的”类加载器加载 native 库,您可以使用仅执行loadLibrary
的单个静态方法创建一个微型类。将此类放在一个额外的jar中,然后将此jar放在共享的Tomcat目录中。然后在Web应用程序中,将对System.loadLibrary
的调用替换为对新的静态方法的调用。这样,OpenCV类的类加载器及其 native 库将匹配,并且可以初始化 native 方法。
编辑:评论员要求的示例
代替
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();
}
}