如何在我的Web应用程序中加载自定义dll文件?我尝试了以下方法,但失败了.
复制system32
文件夹中所有必需的dll 并尝试在Servlet
构造函数中加载其中一个System.loadLibrary
在tomcat_home/shared/lib
和中复制所需的dlltomcat_home/common/lib
所有这些dll都在WEB-INF/lib
web应用程序中
Adam Batkin.. 146
为了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).如果它说的话:PATH
java.library.path
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V
那么Java本身就出现了问题,因为Java无法将应用程序中的本机Java函数映射到实际的本机Java函数.
首先,我会在你的System.loadLibrary()
调用中记录一些日志,看看它是否正确执行.如果它抛出异常或者不在实际执行的代码路径中,那么您将始终获得UnsatisfiedLinkError
上面解释的后一种类型.
作为旁注,大多数人loadLibrary()
使用本机方法将其调用放入类中的静态初始化程序块,以确保它始终只执行一次:
class Foo { static { System.loadLibrary('foo'); } public Foo() { } }
在我的系统(Linux和java7)上,我需要一个`lib`前缀.所以`System.loadLibrary("foo")`需要`libfoo.so`. (16认同)
对于'loadLibrary()`remark,'use"bla"而不是"bla.dll"为+1 - 当你不知道你做错了什么时非常有用. (2认同)
谢谢.当我为Windows更新"PATH"以便它包含具有*.so文件的文件夹时,它对我有用. (2认同)
Alexandre.. 13
在运行时更改'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库路径.
为了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).如果它说的话:PATH
java.library.path
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V
那么Java本身就出现了问题,因为Java无法将应用程序中的本机Java函数映射到实际的本机Java函数.
首先,我会在你的System.loadLibrary()
调用中记录一些日志,看看它是否正确执行.如果它抛出异常或者不在实际执行的代码路径中,那么您将始终获得UnsatisfiedLinkError
上面解释的后一种类型.
作为旁注,大多数人loadLibrary()
使用本机方法将其调用放入类中的静态初始化程序块,以确保它始终只执行一次:
class Foo { static { System.loadLibrary('foo'); } public Foo() { } }
在运行时更改'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库路径.
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.但是,您的webapp现在使用新的ClassLoader运行,并且因为相同的JVM正在运行且JVM不允许对同一DLL进行2次引用,所以无法重新加载它.因此,您的webapp无法访问现有的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) { } }
然后将包含JUST这个编译类的jar放入TOMCAT_HOME/lib文件夹中.
现在,在您的webapp中,您只需强制Tomcat引用此类,这可以像这样简单地完成:
Class.forName("awesome.Foo");
现在您的DLL应该加载到公共类加载器中,并且即使在重新部署之后也可以从您的webapp引用.
合理?
可以在google code,static-dll-bootstrapper上找到工作参考副本.
您可以使用System.load()
提供所需的绝对路径,而不是相应OS的标准库文件夹中的文件.
如果您想要已存在的本机应用程序,请使用System.loadLibrary(String filename)
.如果你想提供自己的,你可能更好用load().
您还应该能够正确使用loadLibrary
该java.library.path
设置.请参阅ClassLoader.java
实现源,显示正在检查的两个路径(OpenJDK)
在问题是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".)