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

java.lang.UnsatisfiedLinkError:本机库XXX.so已加载到另一个类加载器中,java,opencv,tomcat,java-native-interface,Java,Opencv,Tomcat,Java Native Interface,我部署了一个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 alrea

我部署了一个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
我想同时运行这两个应用程序

到目前为止,我一直在尝试:

  • 在一个应用程序中加载了库,并将上述异常捕获到另一个应用程序中
  • 从两个应用程序中删除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)
    

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

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

    现在有一个限制,本地库只能在一个类加载器中加载。Web应用程序使用自己的类加载器,因此如果一个Web应用程序加载了本机库,那么另一个Web应用程序就不能这样做。因此,代码加载本机库不能放在webapp目录中,而必须放在容器(Tomcat)的共享目录中。当您有一个使用上述常规模式编写的类时(
    loadLibrary
    在using class的静态初始值设定项中),将包含该类的jar放入共享目录就足够了。但是,使用OpenCV和web应用程序代码中的
    loadLibrary
    调用,本机库仍将加载到“错误”的类加载器中,您将得到
    未满足的linkerror

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

    编辑:注释者请求的示例

    而不是

    public class WebApplicationClass {
        static {
            System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
        }
    }
    
    使用


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

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

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

    从Tomcat版本
    9.0.13
    8.5.35
    7.0.92
    开始,我们添加了以下选项来解决此问题:

    1) 使用来加载本机库

    e、 g.要加载
    opencv_java343
    库,您可以使用:

    <Listener className="org.apache.catalina.core.JniLifecycleListener"
              libraryName="opencv_java343" />
    

    使用这两个选项中的任何一个都将使用通用类加载器加载本机库,因此它将可用于所有Web应用程序。

    我被困在了这个确切的问题上

    当Tomcat启动时,在Tomcat(v8.5.58)server.xml文件中添加侦听器似乎成功加载了dll文件(至少日志上说是这样),但当您调用本机方法时,它会失败,并出现java.lang.unsatifiedLinkError

    在我的java代码中,无论是否调用“org.apache.tomcat.jni.Library.loadLibrary(“TeighaJavaCore”);”都没有区别,同样的错误仍然存在。我在项目中包括tomcat jni依赖项,以启用“org.apache.tomcat.jni.Library.loadLibrary(“TeighaJavaCore”)”调用。尽管如此,我想在java代码中(在web应用程序级别)不需要调用“org.apache.tomcat.jni.Library.loadLibrary(“TeighaJavaCore”)”,因为TeighaJavaCore.dll将在tomcat启动时自动加载(因为上面的侦听器是在tomcat容器级别定义的)

    我还检查了“org.apache.tomcat.jni.Library.loadLibrary”的源代码,它只调用“System.loadLibrary(libname)”


    第2个应该已经起作用了。你确定你在其他地方删除了它,并且webapp中没有其他jar尝试加载lib?@user2543253请检查我编辑的问题。你能检查
    Highgui
    是否由执行
    loadLibrary
    的同一类加载程序加载吗?否则本机方法将无法初始化。Hii@user2543253,为了简单起见,我删除了我的第二个应用程序。现在我只部署了一个应用程序,它不包含opencv jar。我把它放在/usr/share/tomcat7/lib/目录中。但我仍然收到“java.lang.unsatifiedlinkerror:org.opencv.highgui.highgui.imread_1(Ljava/lang/String;)J”异常。我如何检查“highgui是否由加载库的同一类加载程序加载?”@user2543253如何在项目中使用ToolClassInsparatejarinsharedDirectory类?我需要在我的项目中创建提供的依赖项还是创建相同的类?@rackom我不确定我是否理解这个问题。上面的代码只是一个示例。如果你想使用它,你可以在你自己的项目中创建这样的代码。这个设置不适用于opencv4.0.1,没有任何关于不同之处的想法。我正在使用Spring boot并尝试将opencv4加载到我的应用程序中。谢谢,我不知道。最好使用代码片段和准确的错误消息创建一个新问题。从Tomcat版本9.0.13、8.5.35和7.0.92开始,有一个内置的解决方案。请参阅下面我的答案以了解详细信息。我花了很多时间在这方面,不幸的是,它对我不起作用。在Tomcat(v8.5.38)日志中,我看到
    [info]加载的本机库xxx
    ,但当从部署的webapp调用本机方法时,我得到了
    java.lang.unsatifiedlinkerror:com.package.xxxxyyyyy.methodZzz(Ljava/lang/String;)Ljava/lan
    
    <Listener className="org.apache.catalina.core.JniLifecycleListener"
              libraryName="opencv_java343" />
    
    org.apache.tomcat.jni.Library.loadLibrary("opencv_java343");