2016-04-29 64 views
7

我部署了一個Web應用程序,其中包含以下代碼。java.lang.UnsatisfiedLinkError:原生庫XXX.so已經加載到另一個類加載器

System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME); 

現在,我部署了另一個也具有相同代碼的網絡應用程序。當它試圖加載庫時,會拋出以下錯誤。

Exception in thread "Thread-143" java.lang.UnsatisfiedLinkError: 
Native Library /usr/lib/jni/libopencv_java248.so already loaded in 
another classloader 

我想同時運行這兩個應用程序。

直到現在我曾嘗試:

  1. 加載庫在一個應用程序和異常上面抓進另一個應用程序
  2. 刪除罐子從兩個應用程序,並把opencv.jar到Tomcat的classpath中(即在/ usr /共享/ 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) 
+0

數字2應該已經工作。你確定你在別處刪除了它,並且Web應用程序中沒有其他jar試圖加載lib? – user2543253

+0

@ user2543253請檢查我編輯的問題。 –

+0

你可以檢查'Highgui'是否被加載了'loadLibrary'的同一個類加載器?否則,本地方法不會被初始化。 – user2543253

回答

5

問題是與OpenCV中如何處理本機庫的初始化。

通常,使用本機庫的類將有一個加載該庫的靜態初始化程序。這樣,類和本地庫將始終在同一個類加載器中加載。使用OpenCV,應用程序代碼將加載本機庫。

現在有一個本地庫只能在一個類加載器中加載的限制。 Web應用程序使用它們自己的類加載器,因此如果一個Web應用程序加載了本地庫,另一個Web應用程序就無法做到這一點。因此,加載本機庫的代碼不能放在webapp目錄中,而必須放在容器的(Tomcat)共享目錄中。當你用上面通常的模式編寫的類(使用類的靜態初始化程序中的loadLibrary)時,將包含類的jar放入共享目錄就足夠了。但是,使用OpenCV和Web應用程序代碼中的loadLibrary調用,本地庫仍將加載到「錯誤的」類加載器中,您將獲得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(); 
    } 
} 
-1

作爲javacpp> = 1.3你也可以改變高速緩存文件夾的

代替(由系統定義的財產)在你的戰爭部署聽衆:

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

請注意,雖然本機庫始終是解壓縮的,並且會多次加載(因爲被視爲不同的庫)。

相關問題