java.lang.UnsatisfiedLinkError không có *****. dll trong java.library.path


92

Làm cách nào để tải tệp dll tùy chỉnh trong ứng dụng web của tôi? Tôi đã thử những cách sau:

  • Đã sao chép tất cả các dll bắt buộc trong system32thư mục và cố gắng tải một trong số chúng trong hàm ServlettạoSystem.loadLibrary
  • Đã sao chép dlls bắt buộc vào tomcat_home/shared/libtomcat_home/common/lib

Tất cả những hạt sạn này đều có trong WEB-INF/libứng dụng web

Câu trả lời:


156

Để System.loadLibrary()hoạt động, thư viện (trên Windows, DLL) phải nằm trong một thư mục ở đâu đó trên của bạn PATH hoặc trên đường dẫn được liệt kê trong thuộc tính java.library.pathhệ thống (để bạn có thể khởi chạy Java như vậy java -Djava.library.path=/path/to/dir).

Ngoài ra, đối với loadLibrary(), bạn chỉ định tên cơ sở của thư viện, không có .dllở cuối. Vì vậy, đối với /path/to/something.dll, bạn sẽ chỉ sử dụng System.loadLibrary("something").

Bạn cũng cần phải nhìn vào chính xác UnsatisfiedLinkErrormà bạn đang nhận được. Nếu nó nói một cái gì đó như:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path

thì nó không thể tìm thấy thư viện foo (foo.dll) trong PATHhoặc của bạn java.library.path. Nếu nó nói một cái gì đó như:

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V

thì có điều gì đó không ổn với bản thân thư viện theo nghĩa là Java không thể ánh xạ một hàm Java gốc trong ứng dụng của bạn với đối tác gốc thực sự của nó.

Để bắt đầu, tôi sẽ ghi nhật ký System.loadLibrary()cuộc gọi của bạn để xem liệu cuộc gọi đó có thực thi đúng cách hay không. Nếu nó ném ra một ngoại lệ hoặc không có trong một đường dẫn mã thực sự được thực thi, thì bạn sẽ luôn nhận được loại thứ hai được UnsatisfiedLinkErrorgiải thích ở trên.

Như một phụ chú, hầu hết mọi người đặt loadLibrary()lời gọi của họ vào một khối khởi tạo tĩnh trong lớp với các phương thức gốc, để đảm bảo rằng nó luôn được thực thi chính xác một lần:

class Foo {

    static {
        System.loadLibrary('foo');
    }

    public Foo() {
    }

}

1
Bằng cách đặt tất cả các dlls vào System32 và sử dụng System.loadLibrary ("something") đã hoạt động. Tôi đã làm System.loadLibrary ("something.dll") trước đó. Tại sao nó không thể tải tất cả các dlls từ WEB-INF? Tôi đoán nó tải tất cả các lọ theo mặc định. Tôi có thể làm gì để tải những dlls từ WEB-INF trực tiếp thay vì System32 / xác định chúng trong java.library.path
Ketan Khairnar

2
+1 cho 'sử dụng "bla" thay vì "bla.dll" để nhận loadLibrary()xét-- rất hữu ích khi bạn không biết mình đang làm gì sai.
MarnixKlooster ReinstateMonica

21
Trên hệ thống của tôi (Linux & java7), tôi cần một libtiền tố. Vì vậy, System.loadLibrary("foo")nhu cầu libfoo.so.
kristianlm

2
Cảm ơn. Nó hoạt động với tôi khi tôi cập nhật "PATH" cho các cửa sổ để nó chứa thư mục có tệp * .so.
user613114

Tôi có thể thề rằng OSX cần blah.jnilibvà Linux libblah.so. Chà, hai giờ sau, sau nhiều lần thử, tôi đã đi đến kết luận rằng OSX cũng yêu cầu libtiền tố
Jovan Perovic

15

Thay đổi biến 'java.library.path' trong thời gian chạy là không đủ vì nó chỉ được đọc một lần bởi JVM. Bạn phải đặt lại nó như:

System.setProperty("java.library.path", path);
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);

Vui lòng tham gia chiến lợi phẩm tại: Thay đổi Đường dẫn Thư viện Java khi Runtime .


10

Câu trả lời ban đầu của Adam Batkin sẽ dẫn bạn đến một giải pháp, nhưng nếu bạn triển khai lại ứng dụng web của mình (mà không khởi động lại vùng chứa web của bạn), bạn sẽ gặp phải lỗi sau:

java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
   at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1715)
   at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
   at java.lang.Runtime.load0(Runtime.java:787)
   at java.lang.System.load(System.java:1022)

Điều này xảy ra vì ClassLoader đã tải DLL của bạn ban đầu vẫn tham chiếu đến DLL này. Tuy nhiên, ứng dụng web của bạn hiện đang chạy với ClassLoader mới và vì cùng một JVM đang chạy và một JVM sẽ không cho phép 2 tham chiếu đến cùng một DLL, bạn không thể tải lại nó. Do đó, ứng dụng web của bạn không thể truy cập DLL hiện có và không thể tải tệp mới. Vì vậy, .... bạn đang mắc kẹt.

Tài liệu về ClassLoader của Tomcat phác thảo lý do tại sao ứng dụng web được tải lại của bạn lại chạy trong ClassLoader cô lập mới và cách bạn có thể khắc phục hạn chế này (ở mức rất cao).

Giải pháp là mở rộng giải pháp của Adam Batkin một chút:

   package awesome;

   public class Foo {

        static {
            System.loadLibrary('foo');
        }

        // required to work with JDK 6 and JDK 7
        public static void main(String[] args) {
        }

    }

Sau đó, đặt một jar chứa JUST lớp đã biên dịch này vào thư mục TOMCAT_HOME / lib.

Bây giờ, trong ứng dụng web của bạn, bạn chỉ cần buộc Tomcat tham chiếu đến lớp này, điều này có thể được thực hiện đơn giản như sau:

  Class.forName("awesome.Foo");

Bây giờ DLL của bạn sẽ được tải trong trình tải lớp chung và có thể được tham chiếu từ ứng dụng web của bạn ngay cả sau khi được triển khai lại.

Có lý?

Bạn có thể tìm thấy bản sao tham chiếu đang hoạt động trên mã google, static-dll-bootstrapper .


1
Câu trả lời này là tuyệt vời cho các máy chủ ứng dụng và nên có câu hỏi riêng vì nó bị lãng phí cho câu hỏi này.
JoshDM

8

Bạn có thể sử dụng System.load()để cung cấp một đường dẫn tuyệt đối là những gì bạn muốn, thay vì một tệp trong thư mục thư viện chuẩn cho hệ điều hành tương ứng.

Nếu bạn muốn các ứng dụng gốc đã tồn tại, hãy sử dụng System.loadLibrary(String filename). Nếu bạn muốn cung cấp của riêng mình, bạn có thể tốt hơn với tải ().

Bạn cũng sẽ có thể sử dụng loadLibraryvới java.library.pathbộ chính xác. Xem ClassLoader.javanguồn triển khai hiển thị cả hai đường dẫn đang được kiểm tra (OpenJDK)


Cảm ơn. Sử dụng tải thực sự dễ dàng hơn và trực quan hơn nhiều IMHO. Không thể lấy LoadLibrary để làm việc không có vấn đề gì tôi đã làm ...
Plankalkül

2
Giải pháp này không hoạt động đối với các thư viện tải thư viện gốc của riêng họ.
Justin Skiles

7

Trong trường hợp vấn đề là System.loadLibrary không thể tìm thấy DLL được đề cập, một quan niệm sai lầm phổ biến (được củng cố bởi thông báo lỗi của Java) là thuộc tính hệ thống java.library.path là câu trả lời. Nếu bạn đặt thuộc tính hệ thống java.library.path vào thư mục chứa DLL của bạn, thì System.loadLibrary sẽ thực sự tìm thấy DLL của bạn. Tuy nhiên, nếu DLL của bạn lần lượt phụ thuộc vào các DLL khác, như thường lệ, thì java.library.path không thể giúp được gì, vì việc tải các DLL phụ thuộc được quản lý hoàn toàn bởi hệ điều hành, hệ điều hành không biết gì về java.library. con đường. Do đó, hầu như luôn tốt hơn nếu bỏ qua java.library.path và chỉ cần thêm thư mục DLL của bạn vào LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) hoặc Path (Windows) trước khi bắt đầu JVM.

(Lưu ý: Tôi đang sử dụng thuật ngữ "DLL" theo nghĩa chung của DLL hoặc thư viện được chia sẻ.)


5

Nếu bạn cần tải một tệp liên quan đến một số thư mục mà bạn đã ở đó (như trong thư mục hiện tại), đây là một giải pháp dễ dàng:

File f;

if (System.getProperty("sun.arch.data.model").equals("32")) {
    // 32-bit JVM
    f = new File("mylibfile32.so");
} else {
    // 64-bit JVM
    f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());

4

Dành cho những ai đang tìm kiếm java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path

Tôi đã phải đối mặt với cùng một ngoại lệ; Tôi đã thử mọi thứ và những điều quan trọng để làm cho nó hoạt động là:

  1. Phiên bản chính xác của pdf lib.jar (Trong trường hợp của tôi, đó là phiên bản sai jar được giữ trong thời gian chạy máy chủ)
  2. Tạo một thư mục và giữ jar pdflib trong đó và thêm thư mục vào biến PATH của bạn

Nó hoạt động với tomcat 6.


3
  1. Nếu bạn tin rằng bạn đã thêm một đường dẫn lib gốc vào %PATH%, hãy thử kiểm tra với:

    System.out.println(System.getProperty("java.library.path"))

Nó sẽ hiển thị cho bạn thực sự nếu dll của bạn đang bật %PATH%

  1. Khởi động lại Ý tưởng IDE, ý tưởng này dường như phù hợp với tôi sau khi tôi thiết lập biến env bằng cách thêm nó vào %PATH%

2

Tội nghiệp tôi ! đã dành cả ngày đằng sau vấn đề này. Viết nó xuống đây nếu có cơ quan nào tái tạo vấn đề này.

Tôi đã cố gắng tải theo đề xuất của Adam nhưng sau đó gặp phải trường hợp ngoại lệ AMD64 vs IA 32. JRE VÀ JDK của bạn là 64 bit và bạn đã thêm chính xác nó vào classpath của mình.

Ví dụ làm việc của tôi ở đây: lỗi liên kết không hài lòng


0

Đối với windows, tôi thấy rằng khi tôi tải các phần điền (jd2xsx.dll gọi & ftd2xx.dll) vào thư mục windowws / system32, điều này đã giải quyết được các vấn đề. Sau đó, tôi gặp sự cố với fd2xx.dll mới hơn của mình phải làm với các tham số, đó là lý do tại sao tôi phải tải phiên bản cũ hơn của dll này. Tôi sẽ phải giải thích điều này sau.

Lưu ý: jd2xsx.dll gọi ftd2xx.dll vì vậy chỉ cần đặt đường dẫn cho jd2xx.dll có thể không hoạt động.


0

Tôi đang sử dụng Mac OS X Yosemite và Netbeans 8.02, tôi gặp lỗi tương tự và giải pháp đơn giản mà tôi tìm thấy là như trên, điều này hữu ích khi bạn cần đưa thư viện gốc vào dự án. Vì vậy, làm tiếp theo cho Netbeans:

1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: java -Djava.library.path="your_path"
5.- for example in my case: java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok

Tôi hy vọng nó có thể hữu ích cho ai đó. Liên kết nơi tôi tìm thấy giải pháp ở đây: java.library.path - Nó là gì và cách sử dụng


Hi Alex, tôi có một câu hỏi ở đây là có bất kỳ vấn đề nếu các đường dẫn thư viện bao gồm một số khoảng cách trong đường dẫn ở dòng nàyVM Options: java -Djava.library.path="your_path"
Lokesh Pandey

Mmm Tôi không làm việc với Java trong năm qua nhưng vì xung đột có thể xuất hiện, tôi khuyên bạn nên tránh thêm các khoảng trống trong đường dẫn tệp .
alexventuraio

0

Tôi đã gặp vấn đề tương tự và lỗi là do đổi tên của dll. Có thể xảy ra rằng tên thư viện cũng được viết ở đâu đó bên trong dll. Khi tôi đặt lại tên ban đầu của nó, tôi có thể tải bằngSystem.loadLibrary


0

Nó rất đơn giản chỉ cần viết java -XshowSettings: thuộc tính trên dòng lệnh của bạn trong windows và sau đó dán tất cả các tệp trong đường dẫn được hiển thị bởi java.library.path.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.