在 Java 中在运行时为本机库添加新路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15409223/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 19:29:27  来源:igfitidea点击:

Adding new paths for native libraries at runtime in Java

javajava-native-interfacenative

提问by Sergio

Is it possible to add a new path for native libraries at runtime ?. (Instead of starting Java with the property java.library.path), so a call to System.loadLibrary(nativeLibraryName)will include that path when trying to find nativeLibraryName. Is that possible or these paths are frozen once the JVM has started ?

是否可以在运行时为本机库添加新路径?。(而不是使用属性 java.library.path 启动 Java),因此System.loadLibrary(nativeLibraryName)在尝试 find 时调用将包含该路径nativeLibraryName。一旦 JVM 启动,这是可能的还是这些路径被冻结?

回答by ben75

[This solution don't work with Java 10+]

[此解决方案不适用于 Java 10+]

It seems impossible without little hacking (i.e. accessing private fields of the ClassLoader class)

如果没有一点点黑客攻击,这似乎是不可能的(即访问 ClassLoader 类的私有字段)

This blogprovide 2 ways of doing it.

这个博客提供了两种方法。

For the record, here is the short version.

为了记录,这里是简短的版本。

Option 1:fully replace java.library.path with the new value)

选项 1:用新值完全替换 java.library.path)

public static void setLibraryPath(String path) throws Exception {
    System.setProperty("java.library.path", path);

    //set sys_paths to null so that java.library.path will be reevalueted next time it is needed
    final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
    sysPathsField.setAccessible(true);
    sysPathsField.set(null, null);
}

Option 2:add a new path to the current java.library.path

选项 2:向当前 java.library.path 添加新路径

/**
* Adds the specified path to the java library path
*
* @param pathToAdd the path to add
* @throws Exception
*/
public static void addLibraryPath(String pathToAdd) throws Exception{
    final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
    usrPathsField.setAccessible(true);

    //get array of paths
    final String[] paths = (String[])usrPathsField.get(null);

    //check if the path to add is already present
    for(String path : paths) {
        if(path.equals(pathToAdd)) {
            return;
        }
    }

    //add the new path
    final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
    newPaths[newPaths.length-1] = pathToAdd;
    usrPathsField.set(null, newPaths);
}

回答by Matthew Gerring

I used this in Java 12/13 which should work for any JVM with MethodHandles:

我在 Java 12/13 中使用了它,它应该适用于任何带有 MethodHandles 的 JVM:

Lookup cl = MethodHandles.privateLookupIn(ClassLoader.class, MethodHandles.lookup());
VarHandle sys_paths = cl.findStaticVarHandle(ClassLoader.class, "sys_paths", String[].class);
sys_paths.set(null);

It has the benefit of being a Java API.

它具有作为 Java API 的好处。

It is replaces the:

它取代了:

    final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
    sysPathsField.setAccessible(true);
    sysPathsField.set(null, null);