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

我已经部署了一个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. 在一个应用程序中加载库并将上述exception捕获到另一个应用程序
  2. 从两个应用程序中删除了jar并将opencv.jar放入Tomcat的类路径中(即在/ usr / share / tomcat7 / lib中)。

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

编辑:对于选项二,

 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); 

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

 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) 

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

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

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

从javacpp> = 1.3开始,您还可以更改war部署侦听器中的缓存文件夹(由系统属性定义):

 System.setProperty("org.bytedeco.javacpp.cachedir", Files.createTempDirectory( "javacppnew" ).toString()); 

请注意,本机库始终是解压缩的,并且将被多次加载(因为被视为不同的库)。