次のコードを含む1つの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
これら両方のアプリケーションを同時に実行したいです。
今まで私が試したこと:
しかし、上記のどれもうまくいかず、これを行うための提案はありますか?
編集:オプション2の場合、
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を使用すると、アプリケーションコードはネイティブライブラリをロードします。
現在、ネイティブライブラリは1つのクラスローダーにしかロードできないという制限があります。 Webアプリケーションは独自のクラスローダーを使用するため、あるWebアプリケーションがネイティブライブラリをロードした場合、別のWebアプリケーションはこれを実行できません。したがって、ネイティブライブラリをロードするコードはwebappディレクトリに配置できませんが、コンテナの(Tomcat)共有ディレクトリに配置する必要があります。上記の通常のパターン(クラスを使用する静的イニシャライザのloadLibrary
)で記述されたクラスがある場合、クラスを含むjarを共有ディレクトリに配置するだけで十分です。ただし、OpenCVとloadLibrary
をWebアプリケーションコードで呼び出すと、ネイティブライブラリが「間違った」クラスローダーにロードされたままになり、UnsatisfiedLinkError
が取得されます。
「正しい」クラスローダーにネイティブライブラリをロードさせるには、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();
}
}
Tomcatバージョン_9.0.13
_、_8.5.35
_、および_7.0.92
_の時点で、この問題に対処するために次のオプションを追加しました BZ-628 :
1) JniLifecycleListener
を使用してネイティブライブラリをロードします。
例えば_opencv_Java343
_ライブラリをロードするには、次を使用できます。
_<Listener className="org.Apache.catalina.core.JniLifecycleListener"
libraryName="opencv_Java343" />
_
2)System
の代わりに load()
または loadLibrary()
from _org.Apache.Tomcat.jni.Library
_ を使用します。
例えば.
_org.Apache.Tomcat.jni.Library.loadLibrary("opencv_Java343");
_
これらのオプションのいずれかを使用すると、Common ClassLoaderを使用してネイティブライブラリがロードされるため、すべてのWebアプリで使用できます。