Как повлиять на путь поиска в 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.
Ответ 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....