OpenCV как глобальный модуль JBoss-as
Представление проблемы
Я пытаюсь установить OpenCV как глобальный модуль экземпляра JBoss-as. Версии:
- JBoss-as: 7.1.1 Финал
- OpenCV: 2.4.5 (скомпилировано с поддержкой Java)
Я начал с новой установки Ubuntu Server 12.04 64 бит с только JBoss-as и OpenCV.
преамбула
Java-оболочка OpenCV использует вызовы JNI. Таким образом, необходимы две вещи:
- OpenCV-245.jar
- libopencv_java245.so
И доступно в /usr/share/OpenCV/java/
(относительно установки)
Я также указываю некоторые замечания:
- Установка JBoss правильная (приложения могут быть развернуты и работают)
- Компиляция и установка OpenCV с поддержкой java правильная (класс Java, использующий OpenCV, работает)
- Базовое веб-приложение, использующее OpenCV и развернутое вместе с maven на JBoss-as работает (
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)
Похоже, что OpenCV jar
библиотека найдена, так как из нее возникло исключение. Также он не жалуется на некоторые библиотеки, которые не найдены, как (взято из первой ссылки в конце):
java.lang.UnsatisfiedLinkError: no xxxx in java.library.path
таким образом, я думаю, 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>
Тогда я положил в ту же папку opencv-245.jar
а также libopencv_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>
в моем доме pom.xml
,
Также выкладываю:
System.loadLibrary("opencv_java245");
или нет в коде ничего не меняет.
Дополнительные наблюдения
Я также заметил, что с ear
приложение, состоящее из одного war
и один jar
даже процедура, описанная в пункте 3 в "Преамбуле", не работает и дает то же исключение, что и выше. Может быть, эта информация может помочь.
У кого-то есть какие-то указатели или решения?
Смежные вопросы
3 ответа
Я наконец решаю проблему и пишу здесь ответ, чтобы помочь другим людям.
Проблема была не на пути libopencv_java245.so
, но в JBoss Classloaders.
Для случая, описанного в пункте 3 преамбулы (который работал), ClassLoader, который загружает war
файл тот же, что загружается opencv-245.jar
(который встроен в war
) и призыв к System.loadLibrary("opencv_java245")
в моем коде влияет на этот же ClassLoader, потому что он загрузил класс, содержащий этот вызов метода. Все влияет на один и тот же ClassLoader и все работает.
Теперь причина, почему он не работает с ear
следовать из того факта, что ear
имеет свой собственный ClassLoader, а затем каждое развертывание как другое. Первый ClassLoader развернуть ear
, который содержит opencv-245.jar
зависимости, затем другой ClassLoader развернуть war
содержится в ear
, Потому что звонок System.loadLibrary("opencv_java245")
находится в war
действие этой команды влияет на загрузчик классов war
, но opencv-245.jar
загружается в ear
ClassLoader. Таким образом, при попытке вызвать нативную библиотеку java не может найти ссылку, потому что они находятся на другом ClassLoader.
Наконец, интересным здесь является модуль JBoss. При описании модуля, настроенного в моем начальном вопросе, это JBoss ClassLoader высокого уровня, который загружает opencv-245.jar
, ClassLoader также автоматически узнает, где искать нативные библиотеки: в $MODULE_PATH/lib/linux-x86_64/
, Но проблема в том, чтобы загрузить библиотеку. Призыв к System.loadLibrary("opencv_java245")
должно быть сделано в том же ClassLoader, который зарядил opencv-245.jar
, Таким образом, невозможно загрузить подобную библиотеку в ваш код:
static {
System.loadLibrary("opencv_java245");
}
потому что это повлияет на ClassLoader, который загружает ваш класс, а не на JBoss. Решение состоит в том, чтобы изменить 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
будет иметь эффект один и тот же ClassLoader, который загружает opencv-245.jar
, Тогда родной вызов правильно связан, потому что обе библиотеки, jar
и so
были загружены в тот же ClassLoader.
Если вы используете OpenCV (пакет org.openpnp) 3.4.2+ вместо:
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
вы можете использовать:
OpenCV.loadLocally();
Я использую jboss wildfly, и у меня возникли проблемы при выполнении нескольких развертываний. Родные классы уже были загружены, но это устранило проблему.
Нашел эту ссылку, которая дает инструкции по загрузке Native Libraries
https://docs.jboss.org/author/display/MODULES/Native+Libraries
Добавьте файл 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>