我已经部署了一个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");
我得到了这个例外
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)
答案 0 :(得分:10)
问题在于OpenCV如何处理本机库的初始化。
通常,使用本机库的类将具有加载库的静态初始化程序。这样,类和本机库将始终加载到同一个类加载器中。使用OpenCV,应用程序代码加载本机库。
现在存在一个限制,即只能在一个类加载器中加载本机库。 Web应用程序使用自己的类加载器,因此如果一个Web应用程序加载了本机库,则另一个Web应用程序不能执行相同操作。因此,加载本机库的代码不能放在webapp目录中,但必须放在容器的(Tomcat)共享目录中。如果您使用上面的常规模式编写了一个类(在使用类的静态初始化程序中为loadLibrary
),那么将包含该类的jar放在共享目录中就足够了。但是,使用OpenCV和Web应用程序代码中的loadLibrary
调用,本机库仍将被加载到错误的"类加载器,您将获得UnsatisfiedLinkError
。
使'#34;正确"类加载器加载本机库,您可以创建一个小类,只使用一个静态方法只执行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();
}
}
答案 1 :(得分:0)
从Tomcat版本9.0.13
,8.5.35
和7.0.92
开始,我们添加了以下选项来解决此问题BZ-62830:
1)使用JniLifecycleListener
加载本机库。
例如要加载opencv_java343
库,您可以使用:
<Listener className="org.apache.catalina.core.JniLifecycleListener"
libraryName="opencv_java343" />
2)使用load()
中的loadLibrary()
或org.apache.tomcat.jni.Library
而不是System
。
例如
org.apache.tomcat.jni.Library.loadLibrary("opencv_java343");
使用这些选项中的任何一个都将使用Common ClassLoader加载本机库,因此所有Web应用程序都可以使用它。
答案 2 :(得分:0)
我陷入了这个确切的问题。
在Tomcat启动时,在Tomcat(v8.5.58)server.xml文件中添加侦听器似乎已成功加载dll文件(至少日志这样说),但是当您调用本机方法时,它将失败并显示java.lang .UnsatisfiedLinkError。
无论是否调用“ org.apache.tomcat.jni.Library.loadLibrary(“ TeighaJavaCore”);“在我的Java代码中没有区别,仍然存在相同的错误。我在项目中包含tomcat-jni依赖项,以启用“ org.apache.tomcat.jni.Library.loadLibrary(“ TeighaJavaCore”)“调用。虽然,但我猜没必要在Java代码中(在Web应用程序级别)调用“ org.apache.tomcat.jni.Library.loadLibrary(“ TeighaJavaCore”)“,因为在Tomcat启动时会自动加载TeighaJavaCore.dll(因为上面的侦听器是为此目的而在Tomcat容器级别定义的)
我还在这里检查“ org.apache.tomcat.jni.Library.loadLibrary”的源代码,它只是简单地调用了“ System.loadLibrary(libname)”。
https://github.com/apache/tomcat-native/blob/master/java/org/apache/tomcat/jni/Library.java
答案 3 :(得分:-1)
从javacpp&gt; = 1.3开始,您还可以更改war部署侦听器中的缓存文件夹(由系统属性定义):
System.setProperty("org.bytedeco.javacpp.cachedir",
Files.createTempDirectory( "javacppnew" ).toString());
请注意,本机库始终是解压缩的,并且会被多次加载(因为被视为不同的库)。