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

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

System.loadLibrary("libName"); 

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

我试过了

 System.setProperty("java.library.path", ...) 

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

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

 System.load("fullPath/lib") 

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

我发现的唯一方法如下:

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

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

  1. 您无法更改正在运行的JVM的库路径。
  2. 您不能多次加载本机库…并且您无法卸载本机库以便可以再次加载它: http : //bugs.sun.com/bugdatabase/view_bug.do?video_id = 4171986

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

我需要更改unit testing的dll路径。 我尝试了以下hack并且它有效:

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

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

我试着在我的Mac上为Java应用程序加载一个本机Growl库,其中lib位于我的应用程序的类路径的根目录中:

 System.load(GrowlUtils.class.getResource("/libgrowl.jnilib").getFile().toString()); 

有更简单的方法吗?

是的,提供批处理/脚本文件来启动应用程序。 然后,您可以在批处理/ shell文件中设置正确的路径,甚至可以从环境变量中读取值。 从应用程序内部尝试执行此操作要容易得多。