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

Ser*_*gio 12 java java-native-interface native

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

ben*_*n75 25

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

没有少量黑客攻击似乎是不可能的(即访问ClassLoader类的私有字段)

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

记录中,这是简短版本.

选项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);
}
Run Code Online (Sandbox Code Playgroud)

选项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);
}
Run Code Online (Sandbox Code Playgroud)

  • Java9记录"非法反射访问操作". (2认同)

小智 8

我在 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);
Run Code Online (Sandbox Code Playgroud)

它具有作为 Java API 的好处。

它取代了:

    final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
    sysPathsField.setAccessible(true);
    sysPathsField.set(null, null);
Run Code Online (Sandbox Code Playgroud)

  • 这也不再适用于 JDK 16。我认为没有更多的解决方案 - 干净的方法是使用 System.load。 (6认同)