在 Java 中为运行时的本机库添加新路径
2022-09-02 23:50:08
是否可以在运行时为本机库添加新路径?(而不是以属性 java.library.path 启动 Java),因此在尝试查找 时,调用 将包含该路径。这是可能的,还是一旦JVM启动,这些路径就会被冻结?System.loadLibrary(nativeLibraryName)
nativeLibraryName
是否可以在运行时为本机库添加新路径?(而不是以属性 java.library.path 启动 Java),因此在尝试查找 时,调用 将包含该路径。这是可能的,还是一旦JVM启动,这些路径就会被冻结?System.loadLibrary(nativeLibraryName)
nativeLibraryName
[此解决方案不适用于 Java 10+]
如果没有小的黑客攻击(即访问ClassLoader类的私有字段),这似乎是不可能的。
此博客提供了2种方法。
为了记录在案,这是简短的版本。
选项 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);
}
选项 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);
}
我在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);
它具有作为Java API的好处。
它取代了:
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);