0

Является ли -Djava.library.path=... эквивалентом System.setProperty("java.library.path", ...)?

14

Я загружаю внешнюю библиотеку, которая находится в ./lib. Являются ли два приведенных решения для установки параметра java.library.path эквивалентными?

  1. Установить путь в консоли при выполнении jar:

    java -Djava.library.path=./lib -jar myApplication.jar
    
  2. Установить путь в коде перед загрузкой библиотеки:

    System.setProperty("java.library.path", "./lib");
    

Если они эквивалентны, то почему во втором решении Java не может найти библиотеку, тогда как первое работает корректно?

Если не эквивалентны, есть ли способ установить путь в коде таким образом, чтобы это работало?

4 ответ(ов)

0

В общем, оба подхода имеют один и тот же конечный эффект, так как системное свойство java.library.path устанавливается в значение ./lib.

Тем не менее, некоторые системные свойства оцениваются только в определенные моменты времени, такие как запуск JVM. Если java.library.path попадает в число таких свойств (что и подтверждает ваш эксперимент), то использование второго подхода не приведет к заметным изменениям, кроме как возвращения нового значения при будущих вызовах метода getProperty().

Как правило, использование свойства командной строки -D работает для всех системных свойств, в то время как System.setProperty() срабатывает только для свойств, которые проверяются не только при запуске.

0

Вы можете добавить три строки кода, чтобы решить проблему с загрузкой библиотек в Java:

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

Также не забудьте импортировать java.lang.reflect.Field. Это решение позволит обновить системный путь для загрузки библиотек без перезапуска приложения.

0

Это дополнение к умному ответу Джесси Уэбба выше: https://stackoverflow.com/a/6408467/257299

Для Java 17:

import jdk.internal.loader.NativeLibraries;
final Class<?>[] declClassArr = NativeLibraries.class.getDeclaredClasses();
final Class<?> libraryPaths =
    Arrays.stream(declClassArr)
        .filter(klass -> klass.getSimpleName().equals("LibraryPaths"))
        .findFirst()
        .get();
final Field field = libraryPaths.getDeclaredField("USER_PATHS");
final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup());
final VarHandle varHandle = lookup.findVarHandle(Field.class, "modifiers", int.class);
varHandle.set(field, field.getModifiers() & ~Modifier.FINAL);

Поскольку пакет jdk.internal.loader из модуля java.base обычно недоступен, вам нужно будет добавить "exports" и "opens" как для аргументов компилятора, так и для аргументов выполнения JVM.

--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED

Подробнее можно прочитать здесь:

0

В Temurin JDK установка sys_paths в null не работает и приводит к возникновению NullPointerException.

Следующий код будет работать в Temurin:

Method initLibraryPaths = ClassLoader.class.getDeclaredMethod("initLibraryPaths");
initLibraryPaths.setAccessible(true);
initLibraryPaths.invoke(null);

Этот подход вызывает метод initLibraryPaths через рефлексию и позволяет корректно инициализировать пути к библиотекам, избегая проблемы с NullPointerException.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь