【问题标题】:java.lang.UnsatisfiedLinkError no *****.dll in java.library.pathjava.lang.UnsatisfiedLinkError no *****.dll in java.library.path
【发布时间】:2010-11-27 02:08:47
【问题描述】:

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

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

所有这些 dll 都在网络应用程序的 WEB-INF/lib

【问题讨论】:

    标签: java dll java-native-interface web-applications


    【解决方案1】:

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

    此外,对于loadLibrary(),您指定库的基本名称,末尾不带.dll。因此,对于/path/to/something.dll,您只需使用System.loadLibrary("something")

    您还需要查看您获得的确切 UnsatisfiedLinkError。如果它说类似:

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

    那么它在您的PATHjava.library.path 中找不到foo 库(foo.dll)。如果它说类似:

    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() {
        }
    
    }
    

    【讨论】:

    • 通过将所有 dll 放入 System32 并使用 System.loadLibrary("something") 工作。我之前在做 System.loadLibrary("something.dll") 。为什么它不能从 WEB-INF 加载所有 dll?我猜它默认加载所有罐子。我该怎么做才能直接从 WEB-INF 加载这些 dll 而不是 System32/在 java.library.path 中指定它们
    • +1 for the 'use "bla" instead of "bla.dll" for loadLibrary() remark——当你不知道自己做错了什么时非常有用。
    • 在我的系统(Linux 和 java7)上,我需要一个 lib 前缀。所以System.loadLibrary("foo") 需要libfoo.so
    • 谢谢。当我为 Windows 更新“PATH”以便它包含具有 *.so 文件的文件夹时,它对我有用。
    • 我可以发誓 OSX 需要 blah.jnilib 和 Linux libblah.so。好吧,两个小时后,经过无数次尝试,我得出结论,OSX 确实也需要lib 前缀
    【解决方案2】:

    在运行时更改“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);
    

    请在Changing Java Library Path at Runtime 抽奖。

    【讨论】:

      【解决方案3】:

      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 不允许对同一个 DLL 进行 2 次引用,所以您不能重新加载它。因此,您的 webapp 无法访问现有的 DLL,也无法加载新的 DLL。所以....你被卡住了。

      Tomcat's ClassLoader documentation 概述了为什么您重新加载的 web 应用程序在一个新的隔离 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) {
              }
      
          }
      

      然后将包含 JUST 这个编译类的 jar 放入 TOMCAT_HOME/lib 文件夹中。

      现在,在你的 webapp 中,你只需要强制 Tomcat 引用这个类,就可以这么简单地完成:

        Class.forName("awesome.Foo");
      

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

      有意义吗?

      可以在 google 代码static-dll-bootstrapper 上找到工作参考副本。

      【讨论】:

      • 这个答案非常适合应用服务器,应该有自己的问题,因为它被浪费在这个问题上。
      【解决方案4】:

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

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

      您还应该能够在正确设置java.library.path 的情况下使用loadLibrary。请参阅 ClassLoader.java 以获取显示正在检查的两个路径的实现源 (OpenJDK)

      【讨论】:

      • 谢谢。恕我直言,使用负载实际上更容易,更直观。无论我做什么,都无法让 loadLibrary 工作......
      • 此解决方案不适用于加载自己的本机库的库。
      【解决方案5】:

      如果问题是 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 或共享库。)

      【讨论】:

        【解决方案6】:

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

        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());
        

        【讨论】:

          【解决方案7】:

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

          我遇到了同样的异常;我尝试了一切,重要的事情是:

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

          它适用于 tomcat 6。

          【讨论】:

            【解决方案8】:
            1. 如果你认为你添加了一个原生 lib 的路径到 %PATH%,尝试测试:

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

            如果您的 dll 在 %PATH% 上,它应该会显示您的实际情况

            1. 重新启动 IDE Idea,在我通过将 env 变量添加到 %PATH% 来设置环境变量后,它似乎对我有用

            【讨论】:

              【解决方案9】:

              可怜的我!花了一整天的时间。如果有任何机构复制此问题,请在此处写下来。

              我试图按照 Adam 的建议进行加载,但随后被 AMD64 与 IA 32 异常捕获。如果在按照 Adam 的(无疑是最佳选择)演练工作后无论如何,请尝试使用 64 位版本的最新 jre .确保您的 JRE 和 JDK 是 64 位,并且您已将其正确添加到您的类路径中。

              我的工作示例在这里:unstatisfied link error

              【讨论】:

                【解决方案10】:

                我使用的是 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 – What is it and how to use

                【讨论】:

                • 嗨,Alex,我有一个问题,如果库路径在这一行的路径中包含一些间距,是否有任何问题VM Options: java -Djava.library.path="your_path"
                • 嗯,我去年没有使用 Java,但可能会出现冲突,我建议避免在文件路径中添加空格
                【解决方案11】:

                我遇到了同样的问题,错误是由于重命名了 dll。 库名称也可能写在 dll 中的某处。 当我放回原来的名字时,我可以使用System.loadLibrary进行加载

                【讨论】:

                  【解决方案12】:

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

                  【讨论】:

                    【解决方案13】:

                    首先,您需要确保本机库的目录位于 java.library.path 上。看看如何做到这一点here。然后,您可以致电 System.loadLibrary(nativeLibraryNameWithoutExtension) - 确保不在您的库名称中包含文件扩展名。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2012-12-11
                      • 1970-01-01
                      • 2021-02-24
                      • 1970-01-01
                      • 2013-04-27
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-01-09
                      相关资源
                      最近更新 更多