2016-04-29 15 views
7

Tôi đã triển khai một ứng dụng web có chứa mã sau.java.lang.UnsatisfiedLinkError: Thư viện gốc XXX.so đã được tải trong một trình nạp lớp khác

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

Bây giờ, tôi đã triển khai một ứng dụng web khác có cùng mã. Khi nó cố gắng tải thư viện, nó ném lỗi sau.

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

Tôi muốn chạy cả hai ứng dụng này cùng một lúc.

Đến bây giờ những gì tôi đã cố gắng:

  1. thư viện Loaded trong một ứng dụng và bắt gặp trên ngoại lệ vào một ứng dụng khác
  2. lọ Removed từ cả ứng dụng và đưa opencv.jar vào classpath của Tomcat (tức là trong/usr/share/tomcat7/lib).

Nhưng không có đề xuất nào ở trên có thể làm được điều này?

Edit: cho tùy chọn hai,

System.loadLibrary(Core.NATIVE_LIBRARY_NAME); 

Dòng này hoạt động nhưng được trừ khi tôi thực sự sẽ sử dụng thư viện đó. Đó là khi tôi sau

Mat mat = Highgui.imread("/tmp/abc.png"); 

Và tôi nhận được ngoại lệ này

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

Số 2 nên đã hoạt động. Bạn chắc chắn rằng bạn đã xóa nó ở nơi khác và rằng không có một số jar khác trong webapp tìm cách tải lib? – user2543253

+0

@ user2543253 Vui lòng kiểm tra câu hỏi đã chỉnh sửa của tôi. –

+0

Bạn có thể kiểm tra nếu 'Highgui' được nạp bởi cùng một trình nạp lớp có thực hiện' loadLibrary' không? Nếu không, các phương thức gốc không được khởi tạo. – user2543253

Trả lời

5

Vấn đề là với cách OpenCV xử lý việc khởi tạo thư viện bản xứ.

Thông thường một lớp sử dụng thư viện gốc sẽ có trình khởi tạo tĩnh tải thư viện. Bằng cách này, lớp và thư viện gốc sẽ luôn được tải trong cùng một trình nạp lớp. Với OpenCV, mã ứng dụng sẽ tải thư viện gốc.

Bây giờ có hạn chế rằng một thư viện gốc chỉ có thể được tải trong một trình tải lớp. Các ứng dụng web sử dụng trình nạp lớp của riêng chúng, vì vậy nếu một ứng dụng web đã tải một thư viện riêng, một ứng dụng web khác không thể làm như vậy. Do đó, mã tải các thư viện gốc không thể được đặt trong một thư mục webapp nhưng phải được đặt trong thư mục chia sẻ của thùng chứa (Tomcat). Khi bạn có một lớp được viết với mẫu thông thường ở trên (loadLibrary trong trình khởi tạo tĩnh của lớp đang sử dụng), đủ để đặt jar chứa lớp trong thư mục được chia sẻ. Tuy nhiên, với OpenCV và cuộc gọi loadLibrary trong mã ứng dụng web, thư viện gốc sẽ vẫn được tải trong trình tải lớp "sai" và bạn sẽ nhận được UnsatisfiedLinkError.

Để làm trình tải lớp "đúng" tải thư viện gốc, bạn có thể tạo một lớp học nhỏ với một phương pháp tĩnh chỉ thực hiện loadLibrary. Đặt lớp này vào một cái lọ và đặt cái bình này vào thư mục Tomcat được chia sẻ. Sau đó, trong các ứng dụng web thay thế cuộc gọi đến System.loadLibrary bằng một cuộc gọi đến phương thức tĩnh mới của bạn. Bằng cách này, các trình nạp lớp cho các lớp OpenCV và thư viện gốc của chúng sẽ phù hợp và các phương thức gốc có thể được khởi tạo.

Edit: ví dụ như yêu cầu của một commenter

thay vì

public class WebApplicationClass { 
    static { 
     System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME); 
    } 
} 

sử dụng

public class ToolClassInSeparateJarInSharedDirectory { 
    public static void loadNativeLibrary() { 
     System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME); 
    } 
} 

public class WebApplicationClass { 
    static { 
     ToolClassInSeparateJarInSharedDirectory.loadNativeLibrary(); 
    } 
} 
-1

Tính đến javacpp> = 1.3 bạn cũng có thể thay đổi thư mục cache (được xác định bởi hệ thống tài sản) trong người nghe triển khai chiến dịch của bạn:

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

Lưu ý rằng mặc dù các thư viện gốc luôn được giải nén và sẽ được tải nhiều lần (vì được coi là các libs khác nhau).

Các vấn đề liên quan