java.lang.UnsatisfiedLinkError нет *****. dll в java.library.path - PullRequest
84 голосов
/ 10 сентября 2009

Как я могу загрузить пользовательский файл DLL в свое веб-приложение? Я пробовал следующие способы, но это не удалось.

  • скопировал все необходимые библиотеки в папку system32 и попытался загрузить один из них в Servlet конструктор System.loadLibrary
  • Скопированы необходимые библиотеки в tomcat_home/shared/lib и tomcat_home/common/lib
  • все эти библиотеки находятся в WEB-INF/lib веб-приложения

Ответы [ 13 ]

142 голосов
/ 10 сентября 2009

Чтобы System.loadLibrary() работал, библиотека (в Windows, DLL) должна находиться в каталоге где-то на вашем PATH или по пути, указанному в системном свойстве java.library.path (чтобы вы могли запускать Java как java -Djava.library.path=/path/to/dir).

Кроме того, для loadLibrary() вы указываете базовое имя библиотеки без .dll в конце. Итак, для /path/to/something.dll вы просто должны использовать System.loadLibrary("something").

Вам также нужно взглянуть на тот самый UnsatisfiedLinkError, который вы получаете. Если это говорит что-то вроде:

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

тогда он не может найти библиотеку foo (foo.dll) в вашем PATH или java.library.path. Если это говорит что-то вроде:

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

тогда что-то не так с самой библиотекой в ​​том смысле, что Java не может сопоставить собственную функцию Java в вашем приложении с ее фактическим собственным аналогом.

Для начала, я бы поставил некоторые записи вокруг вашего System.loadLibrary() вызова, чтобы проверить, правильно ли он выполняется. Если оно выдает исключение или не находится в пути кода, который фактически выполняется, то вы всегда получите последний тип UnsatisfiedLinkError, описанный выше.

В качестве идентификатора большинство людей помещают свои вызовы loadLibrary() в статический блок инициализатора в классе с нативными методами, чтобы гарантировать, что он всегда выполняется ровно один раз:

class Foo {

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

    public Foo() {
    }

}
13 голосов
/ 12 февраля 2014

Изменение переменной 'java.library.path' во время выполнения недостаточно, поскольку JVM читает ее только один раз. Вы должны сбросить его как:

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

Пожалуйста, получите лут по адресу: Изменение пути к библиотеке Java во время выполнения .

10 голосов
/ 06 ноября 2012

Исходный ответ Адама Баткина приведет вас к решению, но если вы повторно развернете свое веб-приложение (без перезапуска веб-контейнера), вы должны столкнуться со следующей ошибкой:

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)

Это происходит потому, что ClassLoader, который изначально загрузил вашу DLL, все еще ссылается на эту DLL. Однако ваше веб-приложение теперь работает с новым ClassLoader, и поскольку та же JVM работает, а JVM не разрешает 2 ссылки на одну и ту же DLL, вы не можете перезагрузить ее. Таким образом, ваше веб-приложение не может получить доступ к существующей DLL и не может загрузить новую. Итак ... ты застрял.

Документация Tomcat по ClassLoader описывает, почему ваше перезагруженное веб-приложение работает в новом изолированном ClassLoader и как вы можете обойти это ограничение (на очень высоком уровне).

Решение состоит в том, чтобы немного расширить решение Адама Баткина:

   package awesome;

   public class Foo {

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

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

    }

Затем поместите jar, содержащий JUST этот скомпилированный класс, в папку TOMCAT_HOME / lib.

Теперь в вашем веб-приложении вам просто нужно заставить Tomcat ссылаться на этот класс, что можно сделать так просто:

  Class.forName("awesome.Foo");

Теперь ваша DLL должна быть загружена в общий загрузчик классов, и на нее можно ссылаться из вашего веб-приложения даже после ее повторного развертывания.

Имеет смысл?

Рабочую справочную копию можно найти в коде Google, static-dll-bootstrapper .

7 голосов
/ 17 января 2014

В случае, когда проблема в том, что System.loadLibrary не может найти рассматриваемую DLL, существует одно распространенное заблуждение (подкрепленное сообщением об ошибке Java), что системное свойство java.library.path является ответом. Если вы установите системное свойство java.library.path в каталог, где находится ваша DLL, то System.loadLibrary действительно найдет вашу DLL. Однако, если ваша DLL в свою очередь зависит от других DLL, как это часто бывает, то java.library.path не может помочь, поскольку загрузка зависимых DLL полностью управляется операционной системой, которая ничего не знает о java.library. дорожка. Таким образом, почти всегда лучше обойти java.library.path и просто добавить каталог вашей DLL в LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) или Path (Windows) до запуска JVM.

(Примечание: я использую термин «DLL» в общем смысле DLL или разделяемой библиотеки.)

7 голосов
/ 20 октября 2012

Вы можете использовать System.load() для указания абсолютного пути, который вам нужен, а не файла в стандартной папке библиотеки для соответствующей ОС.

Если вы хотите, чтобы собственные приложения уже существовали, используйте System.loadLibrary(String filename). Если вы хотите предоставить свой собственный, вы, вероятно, лучше с load ().

Вы также можете использовать loadLibrary с java.library.path, установленным правильно. См. ClassLoader.java для источника реализации, показывающего оба проверяемых пути (OpenJDK)

3 голосов
/ 13 июля 2013

Если вам нужно загрузить файл относительно некоторого каталога, в котором вы уже находитесь (как в текущем каталоге), вот простое решение:

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());
2 голосов
/ 20 октября 2012

Плохо мне! провел целый день за этим. Написание здесь, если какой-либо орган повторяет эту проблему.

Я пытался загрузить, как предложил Адам, но потом попался с исключением AMD64 против IA 32. Если в любом случае после работы по прохождению Адама (без сомнения, лучший выбор), попробуйте 64-битную версию последней jre . Убедитесь, что ваш JRE и JDK являются 64-битными, и вы правильно добавили его в путь к классам.

Мой рабочий пример приведен здесь: ошибка неудовлетворительной ссылки

2 голосов
/ 31 августа 2012

Для тех, кто ищет java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path

Я столкнулся с тем же исключением; Я перепробовал все и важные вещи, чтобы он работал:

  1. Правильная версия файла pdf lib.jar (в моем случае это была неверная версия jar, сохраненная во время выполнения сервера)
  2. Создайте папку и сохраните в ней pdflib jar и добавьте папку в переменную PATH

Работает с Tomcat 6.

1 голос
/ 29 октября 2018
  1. Если вы считаете, что добавили путь к собственной lib в% PATH%, проверьте себя еще раз:

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

Это должно показать вам на самом деле, если ваш dll на% PATH%

  1. Перезапустите IDE. Идея, да, мне показалось, что она работает после того, как я настроил переменную env и добавил ее в% PATH%
0 голосов
/ 04 октября 2018

У меня была такая же проблема и ошибка была из-за переименования dll. Может случиться так, что имя библиотеки также записано где-то внутри DLL. Когда я вернул его первоначальное имя, я смог загрузить, используя System.loadLibrary

...