繁体   English   中英

-Djava.library.path=... 等价于 System.setProperty("java.library.path", ...)

[英]Is -Djava.library.path=... equivalent to System.setProperty("java.library.path", ...)

我加载了一个放置在./lib的外部库。 这两种设置 java.library.path 的解决方案是否等效?

  1. 执行 jar 时在控制台中设置路径:

     java -Djava.library.path=./lib -jar myApplication.jar
  2. 在加载库之前在代码中设置路径:

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

如果它们是等价的,为什么在第二个解决方案中 Java 找不到库而第一个解决方案还可以?

如果没有,有没有办法在代码中设置路径?

一般而言,这两种方法具有相同的净效果,因为系统属性java.library.path设置为值./lib

但是 ,某些系统属性仅在特定的时间点评估,例如JVM的启动。 如果 java.library.path在这些属性之中(并且您的实验似乎表明了这一点),那么使用第二种方法将不会产生任何明显的影响,只是在以后调用getProperty()返回新值。

根据经验,使用-D命令行属性对所有系统属性均有效,而System.setProperty()仅对不仅在启动期间进行检查的属性有效。

尽管没有充分说明,但就System.loadLibrary()方法而言, java.library.path系统属性是“只读”属性。 这是一个已报告的错误,但已由Sun关闭,而不是进行修复。 问题在于,JVM的ClassLoader在启动时读取了该属性一次,然后对其进行了缓存,这使我们以后无法通过编程方式对其进行更改。 System.setProperty("java.library.path", anyVal); 除了System.getProperty()方法调用外,将无效。

幸运的是,有人在Sun论坛上发布了一种解决方法 不幸的是,该链接不再起作用,但是我确实在另一个来源上找到了代码 这是您可以用来解决无法设置java.library.path系统属性的代码:

public static void addDir(String s) throws IOException {
    try {
        // This enables the java.library.path to be modified at runtime
        // From a Sun engineer at http://forums.sun.com/thread.jspa?threadID=707176
        //
        Field field = ClassLoader.class.getDeclaredField("usr_paths");
        field.setAccessible(true);
        String[] paths = (String[])field.get(null);
        for (int i = 0; i < paths.length; i++) {
            if (s.equals(paths[i])) {
                return;
            }
        }
        String[] tmp = new String[paths.length+1];
        System.arraycopy(paths,0,tmp,0,paths.length);
        tmp[paths.length] = s;
        field.set(null,tmp);
        System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + s);
    } catch (IllegalAccessException e) {
        throw new IOException("Failed to get permissions to set library path");
    } catch (NoSuchFieldException e) {
        throw new IOException("Failed to get field handle to set library path");
    }
}

警告:这可能不适用于所有平台和/或JVM。

您可以添加三行

 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可以解决问题

这是对上述 Jesse Webb 惊人答案的补充: 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不正常访问,您将需要“出口”和“打开”添加到编译器和JVM运行时ARGS两者

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

在此处阅读更多信息:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM