如何通过Java代码影响System.loadLibrary()的搜索路径?

Phi*_*ler 16 java java-native-interface

在Java项目中,我使用第三方库来加载一些本机库

System.loadLibrary("libName");
Run Code Online (Sandbox Code Playgroud)

我希望能够在我的应用程序中影响此方法的搜索路径,这样用户就不需要在命令行上指定正确的java.library.path值(此值取决于当前的操作系统和建筑).例如在Windows上我想将它设置为"lib/native/windows",在Linux 32bit上设置为"lib/native/linux32"等.

我试过了

System.setProperty("java.library.path", ...)
Run Code Online (Sandbox Code Playgroud)

但是这被忽略了,显然是因为JVM在我的代码运行之前只读取了一次该属性.

我还尝试在使用依赖它的Java库之前加载本机库

System.load("fullPath/lib")
Run Code Online (Sandbox Code Playgroud)

此调用成功,但是当使用System.loadLibrary()再次加载本机库时,仍会存在UnsatisfiedLinkError.

我找到的唯一方法如下:

  • 添加抽象外部库的整个API的接口.
  • 在其余代码中仅使用这些接口.
  • 添加实现接口的类并委托给库.
  • 写一个自己的ClassLoader,那个
    • 覆盖findLibary(),以便在正确的路径中找到本机库
    • 覆盖loadClass()并自己加载外部库和包装层的所有类,而不是像默认的ClassLoader那样尝试委托给它的父类
  • 确保使用普通的ClassLoader加载接口,并使用我自己的ClassLoader加载包装类和外部库.

这是有效的,但我发现它非常复杂,因为我需要添加所有这些接口.有更简单的方法吗?

Ste*_*n C 5

  1. 没有经过批准的方法可以更改正在运行的 JVM 的库路径。
  2. 您无法多次加载本机库...并且无法卸载本机库以便再次加载它:https://bugs.java.com/bugdatabase/view_bug ?bug_id=4171986

根据您上面的评论(特别是第 3 方库的行为),我想说您最好的选择是在启动 JVM 时获取正确的库路径。

请注意,有一种奇怪的方法可以更改库路径(请参阅/sf/answers/1698126881/),但它涉及讨厌的反射,并且据报道它不适用于所有 Java 版本。当然,它依赖于未记录的私有实现细节,ClassLoader这些细节可能会随着一个版本的不同而改变。


Sam*_*mil 5

我需要更改单元测试的dll路径.我尝试了以下hack并且它有效:

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

有关说明,请参阅原始链接.