Как повлиять на путь поиска в System.loadLibrary() через Java-код?

В проекте Java я использую стороннюю библиотеку, которая загружает некоторую собственную библиотеку через

System.loadLibrary("libName");

Я хотел бы иметь возможность влиять на путь поиска этого метода из моего приложения, так что пользователю не нужно указывать правильное значение java.library.path в командной строке (это значение зависит от текущая ОС и архитектура). Например, в Windows я хочу установить его в "lib/native/windows", на Linux 32bit на "lib/native/linux32" и т.д.

Я пробовал

System.setProperty("java.library.path", ...)

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

Я также попытался загрузить собственный libray перед использованием библиотеки Java, которая зависит от нее с помощью

System.load("fullPath/lib")

Этот вызов завершается успешно, но все равно будет UnsatisfiedLinkError, когда загружаемая библиотека снова загружается с помощью System.loadLibrary().

Единственный способ, которым я нашел, это следующее:

  • Добавить интерфейсы, которые абстрагируют весь API внешней библиотеки.
  • Используйте только эти интерфейсы в остальной части кода.
  • Добавить классы, реализующие интерфейсы и делегированные в библиотеку.
  • Напишите собственный ClassLoader, который
    • перезаписывает findLibary(), так что собственная библиотека находится в правильном пути
    • перезаписывает loadClass() и загружает все классы внешней библиотеки и слоя-оболочки самостоятельно, вместо того, чтобы пытаться делегировать ее родительскому элементу, например, класс ClassLoader по умолчанию будет выполнять
  • Убедитесь, что интерфейсы загружены обычным ClassLoader, а классы-оболочки и внешняя библиотека загружаются с помощью моего собственного ClassLoader.

Это работает, но я нахожу его очень сложным и много усилий, потому что мне нужно добавить все эти интерфейсы. Есть ли более простой способ?

Ответы

Ответ 1

  • Вы не можете изменить путь библиотеки для запуска JVM.
  • Вы не можете загружать собственную библиотеку более одного раза... и вы не можете выгрузить собственную библиотеку, чтобы ее можно было снова загрузить: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4171986

Основываясь на ваших комментариях выше (в частности, поведение сторонней библиотеки), я бы сказал, что ваш лучший вариант - получить правильный путь библиотеки при запуске JVM.

Ответ 2

Мне нужно было изменить путь DLL для моих модульных тестов. Я попробовал следующий взлом, и это сработало:

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

Для объяснения смотрите оригинальную ссылку.

Ответ 3

Я попытался выполнить загрузку собственной библиотеки Growl для Java-приложения на моем Mac, где lib находится в корневой папке класса моего приложения:

System.load(GrowlUtils.class.getResource("/libgrowl.jnilib").getFile().toString());

Ответ 4

Есть ли более простой способ?

Да, предоставить пакетные / script файлы для запуска приложения. Затем вы можете установить правильный путь в файле пакета/оболочки или даже прочитать значение из переменной среды. Гораздо проще, чем пытаться сделать это изнутри приложения.

Ответ 5

Хотя технически правильные эти ответы вводят в заблуждение. Установка переменных среды PATH в Windows или LD_LIBRARY_PATH в unix изменится, когда jvm ищет библиотеки: что такое LD_LIBRARY_PATH и как его использовать?

в Linux: экспорт LD_LIBRARY_PATH =/usr/.../затем: Java....