java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll


92

如何在我的Web应用程序中加载自定义dll文件?我尝试了以下方法:

  • 复制system32文件夹中所有必需的dll,并尝试在Servlet构造函数中加载其中一个System.loadLibrary
  • 将所需的dll复制到tomcat_home/shared/libtomcat_home/common/lib

所有这些dll都在WEB-INF/libWeb应用程序中

Answers:


154

为了System.loadLibrary()正常工作,该库(在Windows上为DLL)必须位于系统属性中列出的目录中PATH 您的路径中的某个目录中java.library.path(以便您可以像这样启动Java java -Djava.library.path=/path/to/dir)。

此外,对于loadLibrary(),您可以指定库的基本名称,但不要.dll在末尾添加。因此,/path/to/something.dll您只需使用即可System.loadLibrary("something")

您还需要查看所获得的确切信息UnsatisfiedLinkError。如果显示类似以下内容:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path

则无法在您的或中找到foo库(foo.dll)。如果显示类似以下内容:PATHjava.library.path

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V

那么库本身就出现了问题,即Java无法将应用程序中的本机Java函数映射到其实际本机副本。

首先,我会在您的System.loadLibrary()呼叫周围记录一些日志,以查看该呼叫是否正常执行。如果它引发异常或不在实际执行的代码路径中,那么您将始终得到UnsatisfiedLinkError上面解释的后一种类型。

loadLibrary()附带说明一下,大多数人使用本机方法将调用放入类中的静态初始化程序块中,以确保始终将其执行一次:

class Foo {

    static {
        System.loadLibrary('foo');
    }

    public Foo() {
    }

}

1
通过将所有dll放入System32并使用System.loadLibrary(“ something”)可以正常工作。我之前在做System.loadLibrary(“ something.dll”)。为什么不能从WEB-INF加载所有dll?我猜它默认加载所有jar。我能做些什么来加载从WEB-INF这些DLL文件,而不是直接System32下的/在指定的java.library.path他们
科坦Khairnar

2
+1表示'使用“ bla”而不是“ bla.dll”进行loadLibrary()备注-当您不知道自己在做什么错时,此功能非常有用。
MarnixKlooster恢复状态莫妮卡

20
在我的系统(Linux和Java7)上,我需要一个lib前缀。所以System.loadLibrary("foo")需要libfoo.so
kristianlm

2
谢谢。当我更新Windows的“ PATH”以使其包含具有* .so文件的文件夹时,它对我有用。
user613114

15

在运行时更改'java.library.path'变量是不够的,因为JVM只能读取一次。您必须像这样重置它:

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

请在以下位置进行抢劫:在运行时更改Java库路径


10

亚当·巴特金(Adam Batkin)的原始答案将带您找到解决方案,但是,如果重新部署Web应用程序(而不重新启动Web容器),则应遇到以下错误:

java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
   at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1715)
   at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
   at java.lang.Runtime.load0(Runtime.java:787)
   at java.lang.System.load(System.java:1022)

发生这种情况的原因是,最初加载DLL的ClassLoader仍引用此DLL。但是,您的Web应用程序现在正在使用新的ClassLoader运行,并且由于正在运行相同的JVM,并且JVM不允许2对同一DLL的引用,因此无法重新加载它。因此,您的Web应用程序无法访问现有的DLL,也无法加载新的DLL。所以...。

Tomcat的ClassLoader文档概述了重新加载的Webapp为什么要在新的隔离的ClassLoader中运行,以及如何解决此限制(在很高的层次上)。

解决方案是将Adam Batkin的解决方案扩展一点:

   package awesome;

   public class Foo {

        static {
            System.loadLibrary('foo');
        }

        // required to work with JDK 6 and JDK 7
        public static void main(String[] args) {
        }

    }

然后将一个仅包含此已编译类的jar放入TOMCAT_HOME / lib文件夹中。

现在,在您的webapp中,您只需要强制Tomcat引用该类,就可以像这样简单地完成:

  Class.forName("awesome.Foo");

现在,您的DLL应该已加载到通用的类加载器中,并且即使重新部署后也可以从您的web应用程序中引用它。

合理?

可以在Google代码static-dll-bootstrapper上找到有效的参考副本。


1
该答案对于应用程序服务器非常有用,并且应该有自己的问题,因为它浪费在此问题上。
JoshDM

8

您可以使用System.load()提供所需路径的绝对路径,而不是提供各个操作系统的标准库文件夹中的文件。

如果要使用本机应用程序,请使用System.loadLibrary(String filename)。如果您想提供自己的,最好使用load()。

您还应该能够正确使用loadLibraryjava.library.path套件。请参阅ClassLoader.java以获取实现源,其中显示了两个被检查的路径(OpenJDK)


谢谢。实际上,使用负载更容易,更直观,恕我直言。无法获取LoadLibrary来的工作,无论我做什么...
Plankalkül

2
该解决方案不适用于加载自己的本机库的库。
贾斯汀·斯基尔斯

7

如果问题是System.loadLibrary找不到有问题的DLL,则一个常见的误解(由Java的错误消息强化)是系统属性java.library.path是答案。如果将系统属性java.library.path设置为DLL所在的目录,则System.loadLibrary确实会找到您的DLL。但是,如果您的DLL(通常)又依赖于其他DLL,则java.library.path无法提供帮助,因为从属DLL的加载完全由操作系统管理,而操作系统对java.library一无所知。路径。因此,在启动JVM之前,绕过java.library.path并简单地将DLL的目录添加到LD_LIBRARY_PATH(Linux),DYLD_LIBRARY_PATH(MacOS)或Path(Windows)几乎总是更好的选择。

(注意:我在DLL或共享库的一般意义上使用术语“ DLL”。)


5

如果您需要加载相对于某个目录的文件(例如当前目录中的文件),这是一个简单的解决方案:

File f;

if (System.getProperty("sun.arch.data.model").equals("32")) {
    // 32-bit JVM
    f = new File("mylibfile32.so");
} else {
    // 64-bit JVM
    f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());

4

对于那些正在寻找 java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path

我面临着同样的例外;我尝试了所有事情,并使它起作用的重要事情是:

  1. pdf lib.jar的正确版本(在我的情况下,服务器运行时中保存的版本jar错误)
  2. 创建一个文件夹并将pdflib jar保存在其中,然后将该文件夹添加到PATH变量中

它与tomcat 6一起使用。


3
  1. 如果您相信已向添加了本机lib的路径%PATH%,请尝试使用以下方法进行测试:

    System.out.println(System.getProperty("java.library.path"))

它应该实际显示您的dll是否打开 %PATH%

  1. 重新启动IDE Idea,在将env变量添加到 %PATH%

2

可怜的我 !花费了一整天的时间。如果有人重复此问题,请写下来。

我试图按照Adam的建议进行加载,但随后陷入了AMD64 vs IA 32异常的情况。如果在按照Adam(毫无疑问是最佳选择)演练工作后遇到任何情况,请尝试安装64位版本的最新jre。您的JRE和JDK是64位的,并且您已正确将其添加到类路径中。

我的工作示例在这里:未统计的链接错误


0

对于Windows,我发现当我将filles(jd2xsx.dll调用&ftd2xx.dll)加载到windowws / system32文件夹中时,此问题已解决。然后,我的较新的fd2xx.dll与参数有关,这就是为什么我必须加载该dll的较旧版本的问题。稍后我将不得不对此进行补充。

注意:jd2xsx.dll调用ftd2xx.dll,因此仅设置jd2xx.dll的路径可能不起作用。


0

我使用的是Mac OS X Yosemite和Netbeans 8.02,遇到了相同的错误,发现的简单解决方案与上面类似,当您需要在项目中包括本机库时,这很有用。Netbeans的下一个也是:

1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: java -Djava.library.path="your_path"
5.- for example in my case: java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok

我希望它对某人有用。我找到解决方案的链接在这里: java.library.path –它是什么以及如何使用


嗨,Alex,我有一个问题,如果库路径在此行的路径中包含一些间距,是否有任何问题VM Options: java -Djava.library.path="your_path"
Lokesh Pandey

嗯,我去年没有使用Java,但是由于可能会出现冲突,我建议避免在文件路径中添加空格
alexventuraio


0

很简单,只需在Windows的命令行中编写java -XshowSettings:properties,然后将所有文件粘贴到java.library.path显示的路径中即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.