Str*_*bra 5 java java-native-interface jboss opencv
我尝试将OpenCV安装为JBoss-as实例的全局模块.版本是:
我从全新安装的Ubuntu Server 12.04 64位开始,只安装了JBoss-as和OpenCV.
OpenCV java包装器使用JNI调用.因此需要两件事:
可用/usr/share/OpenCV/java/(关于安装)
我还指出了一些意见:
opencv-245.jar作为依赖项pom.xml,因此被打包到其中war)一旦我将OpenCV定义为JBoss全局模块(<scope>provided</scope>在pom.xml中设置),就会引发此异常:
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)
Run Code Online (Sandbox Code Playgroud)
似乎jar找到了OpenCV 库,因为它引发了异常.此外,它没有抱怨一些未找到的库(从最后的第一个链接获取):
java.lang.UnsatisfiedLinkError: no xxxx in java.library.path
Run Code Online (Sandbox Code Playgroud)
因此我猜这libopencv_java245.so不是问题.精确配置如下所述.
我org.opencv在modules/org/opencv/main/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"/>
</resources>
<dependencies>
<module name="javax.api"/>
</dependencies>
</module>
Run Code Online (Sandbox Code Playgroud)
然后我放入相同的文件夹opencv-245.jar,也libopencv_java245.so放在lib/linux-x86_64/子文件夹中(如本机库中所述)
要将此模块定义为全局我修改为standalone/configuration/standalone.xml:
<subsystem xmlns="urn:jboss:domain:ee:1.0">
<global-modules>
<module name="org.opencv" slot="main"/>
</global-modules>
</subsystem>
Run Code Online (Sandbox Code Playgroud)
最后使用我设置的全局模块src/main/webapp/WEB-INF/jboss-deployment-structure.xml:
<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.opencv" />
</dependencies>
</deployment>
</jboss-deployment-structure>
Run Code Online (Sandbox Code Playgroud)
我还提醒说我已经放入<scope>provided</scope>了我的专家pom.xml.
另外,放:
System.loadLibrary("opencv_java245");
Run Code Online (Sandbox Code Playgroud)
或不在代码中不会改变任何东西.
我还注意到,对于ear由一个war和一个组成的应用程序,jar即使"前言"中第3点中描述的过程也不起作用,并给出与上面相同的例外.也许这些信息可以提供帮助
有人有一些指针或解决方案吗?
我终于解决了问题并在这里写下了帮助其他人的答案.
问题不在于libopencv_java245.so,而是在JBoss类加载器中.
对于Preamble point 3(有效)中描述的情况,加载war文件的ClassLoader 与加载opencv-245.jar(嵌入到文件中)相同war,并且对System.loadLibrary("opencv_java245")我的代码的调用对同一个ClassLoader有影响,因为它已加载包含此方法的类调用.所有这些都对同一个ClassLoader有影响,一切正常.
现在之所以没有使用ear后续工作的原因是a ear有自己的ClassLoader,然后每个子部署作为另一个.第一个ClassLoader部署ear,其中包含opencv-245.jardependecy,然后另一个ClassLoader部署war包含到ear.因为调用System.loadLibrary("opencv_java245")是在war,所以这个命令的效果对ClassLoader有影响war,但是opencv-245.jar被加载到earClassLoader中.因此,当尝试调用本机库时,java无法找到该链接,因为它们位于不同的ClassLoader上.
最后,这里的兴趣点是JBoss模块.在描述我在初始问题中配置的模块时,这是一个加载的高级JBoss ClassLoader opencv-245.jar.ClassLoader还将自动知道在哪里搜索本机库:in $MODULE_PATH/lib/linux-x86_64/.但问题是加载库.调用System.loadLibrary("opencv_java245")必须在收费的同一个ClassLoader中完成opencv-245.jar.因此,无法在代码中加载这样的库:
static {
System.loadLibrary("opencv_java245");
}
Run Code Online (Sandbox Code Playgroud)
因为它会影响已加载Class的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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在课堂上你可以:
static {
Loader.loadLibrary("opencv_java245");
}
Run Code Online (Sandbox Code Playgroud)
System.loadLibrary放入的调用opencv-245.jar将生成一个加载的同一个ClassLoader opencv-245.jar.然后本机调用被正确链接,因为库,the jar和the so都被加载到同一个ClassLoader中.