it-swarm.com.de

java.lang.UnsatisfiedLinkError no *****. dll in Java.library.path

Wie kann ich eine benutzerdefinierte DLL-Datei in meine Webanwendung laden? Ich habe folgende Möglichkeiten ausprobiert, aber es scheitert.

  • kopierte alle benötigten dlls im system32-Ordner und versuchte, eine davon in Servlet constructor zu laden System.loadLibrary
  • Erforderliche DLLs in Tomcat_home/shared/lib und Tomcat_home/common/lib kopiert
  • alle diese DLLs befinden sich in WEB-INF/lib der Webanwendung
83
Ketan Khairnar

Damit System.loadLibrary() funktioniert, muss sich die Bibliothek (unter Windows eine DLL) in einem Verzeichnis irgendwo in Ihrer PATH oder in einem Pfad befinden, der in der Systemeigenschaft Java.library.path aufgeführt ist (damit Sie Java wie Java -Djava.library.path=/path/to/dir starten können).

Außerdem geben Sie für loadLibrary() den Basisnamen der Bibliothek ohne den .dll am Ende an. Für /path/to/something.dll würden Sie also einfach System.loadLibrary("something") verwenden.

Sie müssen auch die genaue UnsatisfiedLinkError betrachten, die Sie erhalten. Wenn es so etwas sagt:

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

dann kann sie die foo library (foo.dll) in Ihrer PATH oder Java.library.path nicht finden. Wenn es so etwas sagt:

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

dann ist etwas mit der Bibliothek in dem Sinne falsch, dass Java eine native Java-Funktion in Ihrer Anwendung nicht ihrem eigentlichen nativen Gegenstück zuordnen kann.

Zu Beginn würde ich einige Protokolle in Ihren System.loadLibrary()-Aufruf einfügen, um zu sehen, ob dies ordnungsgemäß ausgeführt wird. Wenn es eine Ausnahme auslöst oder sich nicht in einem tatsächlich ausgeführten Codepfad befindet, wird immer der letztgenannte Typ von UnsatisfiedLinkError angezeigt.

Als Randbemerkung legen die meisten Benutzer ihre loadLibrary()-Aufrufe in einen statischen Initialisierungsblock in der Klasse mit den systemeigenen Methoden, um sicherzustellen, dass sie immer genau einmal ausgeführt werden:

class Foo {

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

    public Foo() {
    }

}
140
Adam Batkin

Das Ändern der Variable 'Java.library.path' zur Laufzeit ist nicht ausreichend, da sie von JVM nur einmal gelesen wird. Sie müssen es zurücksetzen wie:

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);

Bitte nehmen Sie eine Beute unter: Ändern des Java-Bibliothekspfads zur Laufzeit .

11
Alexandre

Die ursprüngliche Antwort von Adam Batkin führt Sie zu einer Lösung. Wenn Sie jedoch Ihre Webapp neu implementieren (ohne den Webcontainer neu zu starten), sollten Sie die folgende Fehlermeldung erhalten:

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)

Dies geschieht, weil der ClassLoader, der Ihre DLL ursprünglich geladen hat, immer noch auf diese DLL verweist. Ihre Webapp läuft jedoch jetzt mit einem neuen ClassLoader, und da dieselbe JVM ausgeführt wird und eine JVM keine 2 Verweise auf dieselbe DLL zulässt, können Sie sie nicht reload. Daher kann Ihre Webapp nicht auf die vorhandene DLL zugreifen und keine neue laden. Also ... du bist festgefahren. 

Tomcat ClassLoader-Dokumentation beschreibt, warum Ihre neu geladene Webapp in einem neuen isolierten ClassLoader ausgeführt wird und wie Sie diese Einschränkung umgehen können (auf sehr hohem Niveau).

Die Lösung besteht darin, die Lösung von Adam Batkin etwas zu erweitern:

   package awesome;

   public class Foo {

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

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

    }

Platzieren Sie dann eine Dose mit JUST dieser kompilierten Klasse im Ordner Tomcat_HOME/lib.

Jetzt müssen Sie in Ihrer Webapp nur Tomcat zwingen, auf diese Klasse zu verweisen. Dies kann auf folgende einfache Weise geschehen:

  Class.forName("awesome.Foo");

Jetzt sollte Ihre DLL in den allgemeinen Klassenladeprogramm geladen werden und kann auch nach der erneuten Bereitstellung von Ihrer WebApp referenziert werden.

Sinn ergeben?

Eine funktionierende Referenzkopie befindet sich auf dem Google-Code static-dll-bootstrapper .

10
Matt M

Sie können System.load() verwenden, um einen absoluten Pfad anzugeben, der Ihren Wünschen entspricht, und nicht eine Datei im Standard-Bibliotheksordner für das jeweilige Betriebssystem.

Wenn Sie bereits vorhandene Anwendungen verwenden möchten, verwenden Sie System.loadLibrary(String filename) . Wenn Sie Ihre eigenen angeben möchten, sind Sie wahrscheinlich besser mit load ().

Sie sollten auch loadLibrary verwenden können, wenn Java.library.path richtig eingestellt ist. Siehe ClassLoader.Java für die Implementierungsquelle, die beide geprüften Pfade zeigt (OpenJDK)

7

In dem Fall, dass das Problem darin besteht, dass System.loadLibrary die fragliche DLL nicht finden kann, ist ein häufiges Missverständnis (verstärkt durch die Fehlermeldung von Java), dass die Systemeigenschaft Java.library.path die Antwort ist. Wenn Sie die Systemeigenschaft Java.library.path auf das Verzeichnis setzen, in dem sich Ihre DLL befindet, wird System.loadLibrary Ihre DLL tatsächlich finden. Wenn Ihre DLL jedoch wiederum von anderen DLLs abhängt, wie dies häufig der Fall ist, kann Java.library.path nicht helfen, da das Laden der abhängigen DLLs vollständig vom Betriebssystem verwaltet wird, von dem nichts bekannt ist Java.library.path. Daher ist es fast immer besser, Java.library.path zu umgehen und das Verzeichnis Ihrer DLL vor dem Starten der JVM einfach zu LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) oder Path (Windows) hinzuzufügen.

(Hinweis: Ich verwende den Begriff "DLL" im allgemeinen Sinne von DLL oder einer gemeinsam genutzten Bibliothek.)

6
Ian Emmons

Wenn Sie eine Datei laden müssen, die relativ zu einem Verzeichnis ist, in dem Sie sich bereits befinden (wie im aktuellen Verzeichnis), ist hier eine einfache Lösung:

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());
3
Rick C. Hodgin

Für diejenigen, die nach Java.lang.UnsatisfiedLinkError: no pdf_Java in Java.library.path suchen

Ich war mit derselben Ausnahme konfrontiert. Ich habe alles versucht und wichtige Dinge, damit es funktioniert:

  1. Korrekte Version von pdf lib.jar (In meinem Fall wurde die falsche Version in der Server-Laufzeit jar gehalten)
  2. Erstellen Sie einen Ordner und behalten Sie den pdflib jar darin, und fügen Sie den Ordner in Ihre PATH-Variable ein

Es hat mit Tomcat 6 funktioniert.

2

Ich armer ! Ich verbrachte einen ganzen Tag hinter dem hier. Schreiben Sie es hier unten, wenn irgendein Körper dieses Problem repliziert.

Ich habe versucht zu laden, wie Adam vorgeschlagen hatte, aber dann mit AMD64 vs. IA 32-Ausnahme erwischt wurde. Wenn Sie auf jeden Fall nach Adams Arbeit (zweifellos die beste Wahl) durchlaufen, versuchen Sie, eine 64-Bit-Version der neuesten Version von jre zu erhalten Ihr JRE UND JDK sind 64-Bit und Sie haben es korrekt zu Ihrem Klassenpfad hinzugefügt.

Mein Arbeitsbeispiel geht hier: unzufriedener Linkfehler

2
sayannayas
  1. Wenn Sie der Meinung sind, dass Sie% PATH% einen Pfad der nativen lib hinzugefügt haben, testen Sie sich noch einmal, indem Sie:

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

Es sollte Ihnen tatsächlich zeigen, wenn sich Ihre DLL auf% PATH% befindet.

  1. Starten Sie IDE neu. Idee, ja, es schien für mich zu funktionieren, nachdem ich die env-Variable mit dem Hinzufügen von% PATH% eingerichtet habe.
1
AlexPes

Bei Windows habe ich festgestellt, dass beim Laden der Filles (jd2xsx.dll und ftd2xx.dll) in den Ordner windowws/system32 die Probleme gelöst wurden. Ich hatte dann ein Problem mit meiner neueren fd2xx.dll, die mit Parametern zu tun hatte, weshalb ich die ältere Version dieser DLL laden musste. Ich werde das später herausholen müssen.

Hinweis: Die Datei jd2xsx.dll ruft die Datei ftd2xx.dll auf. Das Festlegen des Pfads für die Datei jd2xx.dll funktioniert möglicherweise nicht.

0
Dan Carte

Ich hatte das gleiche Problem und der Fehler war auf eine Umbenennung der DLL zurückzuführen. Es konnte vorkommen, dass der Bibliotheksname auch irgendwo in die DLL geschrieben wurde System.loadLibrary verwenden

0

Ich verwende Mac OS X, Yosemite und Netbeans 8.02. Ich habe den gleichen Fehler erhalten und die einfache Lösung, die ich gefunden habe, ist wie oben. Dies ist nützlich, wenn Sie die native Bibliothek in das Projekt aufnehmen möchten. Machen Sie das nächste für 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

Ich hoffe, es könnte für jemanden nützlich sein .. Der Link, wo ich die Lösung gefunden habe, ist hier: Java.library.path - Was ist das und wie benutzt man

0
Alex Ventura

Schreiben Sie einfach Java -XshowSettings: properties in Ihre Befehlszeile in Windows und fügen Sie dann alle Dateien in den Pfad ein, der in Java.library.path angegeben ist.

0
Ali Sasoli