OpenCV作为JBoss-as全局模块

5

问题陈述

我尝试将OpenCV安装为JBoss-as实例的全局模块。版本如下:

  • JBoss-as: 7.1.1 Final
  • OpenCV: 2.4.5(带Java支持编译)

我从一个只安装了JBoss-as和OpenCV的Ubuntu Server 12.04 64位新安装开始。

引言

OpenCV Java包装器使用JNI调用。因此需要以下两个文件:

  • opencv-245.jar
  • libopencv_java245.so

并位于/usr/share/OpenCV/java/(根据安装位置而定)中。

我也指出了一些观察结果:

  1. JBoss的安装是正确的(可以部署应用程序并且运行正常)
  2. 使用Java支持编译和安装OpenCV的操作是正确的(使用OpenCV的Java类也能正常工作)
  3. 使用OpenCV的基本Web应用程序已经使用Maven部署在JBoss-as上运行正常,opencv-245.jarpom.xml中被列为依赖项,并随war打包)

问题描述

一旦我将OpenCV定义为JBoss全局模块(在pom.xml中设置<scope>provided</scope>),就会引发以下异常:

java.lang.UnsatisfiedLinkError: org.opencv.core.Mat.n_Mat()J
    org.opencv.core.Mat.n_Mat(Native Method)
    org.opencv.core.Mat.<init>(Mat.java:441)
    WS.printMessage(WS.java:15)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method.invoke(Method.java:616)
    org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:155)
    org.jboss.resteasy.core.ResourceMethod.invokeOnTarget(ResourceMethod.java:257)
    org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:222)
    org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:211)
    org.jboss.resteasy.core.SynchronousDispatcher.getResponse(SynchronousDispatcher.java:525)
    org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:502)
    org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:119)
    org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:208)
    org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55)
    org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:50)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:847)

看起来 OpenCV 的 jar 库已找到,因为异常是由它引发的。而且它没有像第一个链接中提到的那样抱怨找不到某些库:

java.lang.UnsatisfiedLinkError: no xxxx in java.library.path

因此,我猜测libopencv_java245.so不是问题所在。具体配置如下。

配置

我在modules/org/opencv/main/module.xml中定义了org.opencv模块:

<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.opencv">
    <resources>
        <resource-root path="opencv-245.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
    </dependencies>
</module>

然后我将opencv-245.jarlibopencv_java245.so放在同一个文件夹中,还放在了lib/linux-x86_64/子文件夹中(如Native Library所述)。

为了将该模块定义为全局模块,我在standalone/configuration/standalone.xml中进行了修改:

<subsystem xmlns="urn:jboss:domain:ee:1.0">
    <global-modules>
        <module name="org.opencv" slot="main"/>
    </global-modules>
</subsystem>

最后,为了使用我在 src/main/webapp/WEB-INF/jboss-deployment-structure.xml 中设置的全局模块:

<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="org.opencv" />
        </dependencies>
    </deployment>
</jboss-deployment-structure>

我提醒一下,我已将<scope>provided</scope>放入我的Maven pom.xml中。
此外,还可以加入:
System.loadLibrary("opencv_java245");

在代码中使用或不使用不会有任何变化。

额外观察

我还注意到,对于一个由一个war和一个jar组成的ear应用程序,即使按照“前言”中第3点所述的过程也无法工作,并且会产生与上述相同的异常。也许这些信息可以帮助解决问题。

有人有一些指针或解决方案吗?

相关问题

3个回答

6

我终于解决了问题,并在此处写下答案来帮助其他人。

问题不在于 libopencv_java245.so 的路径,而是在于 JBoss 类加载器。

对于前言中描述的第3点情况(可行的情况),加载 war 文件的类加载器与加载嵌入到 war 中的 opencv-245.jar 的类加载器是相同的,而我的代码中对 System.loadLibrary("opencv_java245") 的调用会影响这个相同的类加载器,因为它已经加载了包含这个方法调用的类。所有这些都会影响相同的类加载器,一切正常运作。

现在为什么使用 ear 时无法工作,是因为 ear 有自己的类加载器,然后每个子部署都有一个类加载器。第一个类加载器部署了包含 opencv-245.jar 依赖的 ear,然后另一个类加载器部署了包含在 ear 内的 war。由于调用 System.loadLibrary("opencv_java245")war 中,因此此命令的效果会影响到 war 的类加载器,但 opencv-245.jar 被加载到 ear 的类加载器中。因此,在尝试调用本机库时,Java 找不到链接,因为它们在不同的类加载器上。

最后,这里的重点是 JBoss 模块。当描述一个模块配置时,它会作为高级别 JBoss 类加载器加载 opencv-245.jar。类加载器还会自动知道在哪里搜索本机库:$MODULE_PATH/lib/linux-x86_64/。但问题在于加载库。必须在已经加载了 opencv-245.jar 的相同类加载器中使用 System.loadLibrary("opencv_java245")。因此,您无法在代码中像这样加载库:

static {
    System.loadLibrary("opencv_java245");
}

因为这会影响到已经加载了你的类的ClassLoader,而不是JBoss的ClassLoader。解决方法是修改opencv-245.jar,并在其中添加一个org.opencv.core.Loader类,例如,该类只有一个方法:

package org.opencv.core

class Loader
{
    public static void loadLibrary(String name)
    {
        System.loadLibrary(name);
    }
}

然后在你的类中,你可以添加:

static {
    Loader.loadLibrary("opencv_java245");
}

System.loadLibrary方法被放置在opencv-245.jar中,将会对加载opencv-245.jar的ClassLoader产生影响。因此,原生调用能够正确地链接,因为jarso库都是在同一个ClassLoader中加载的。


你的回答有所改进,现在在OpenCV 3中有一个用于OSGi的类,但对我们的目的也适用。因此,不需要注入该类,只需调用 new org.opencv.osgi.OpenCVNativeLoader().init(); 即可。 - Carlos Rafael Ramirez
1
@carlos-rafael-ramirez 我不再使用OpenCV或Java了。我将这个答案转换为社区维基,随意改进它! - StreakyCobra

1
如果您使用的是 OpenCV(org.openpnp 包)3.4.2+,而不是:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

你可以使用:

OpenCV.loadLocally();

我正在使用jboss wildfly,当进行多个部署时遇到了问题。本地类已经加载,但这解决了问题。


0
将libopencv_java245.so文件添加到您为OpenCV模块创建的同一目录中。然后将其添加为资源,以便将其添加到类路径并在运行时可用。
因此,您的module.xml现在应该如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.0" name="org.opencv">
    <resources>
        <resource-root path="opencv-245.jar"/>
        <resource-root path="."/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
    </dependencies>
</module>

抛出异常:Caused by: org.jboss.modules.ModuleLoadException: Error loading module from /opt/jboss-as/modules/org/opencv/main/module.xml Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[5,53] Message: Failed to add resource root 'libopencv_java245.so' at path 'libopencv_java245.so' - StreakyCobra
我编辑了module.xml文件,将当前jar文件目录的路径包含在内。确保.so文件与该目录位于同一目录下,我认为它应该可以工作。如果不能,请告诉我。 - Mr. Will
我也找到了一个可能有帮助的论坛帖子 https://community.jboss.org/thread/206389 - Mr. Will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接