Java 在OSGi包中加载DLL(使用JNA)

Java 在OSGi包中加载DLL(使用JNA),java,osgi,jna,Java,Osgi,Jna,OSGi找不到我的DLL文件,我似乎不知道为什么 目前,我将DLL文件(foo.DLL)放在捆绑包的根目录下,我还尝试将其放在libs目录下 相关捆绑包的清单如下所示: Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: foobundle Bundle-SymbolicName: com.foo.bar Bundle-Version: 1.0.0 Bundle-Vendor: me Import-Package: com.s

OSGi找不到我的DLL文件,我似乎不知道为什么

目前,我将DLL文件(
foo.DLL
)放在捆绑包的根目录下,我还尝试将其放在
libs
目录下

相关捆绑包的清单如下所示:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: foobundle
Bundle-SymbolicName: com.foo.bar
Bundle-Version: 1.0.0
Bundle-Vendor: me
Import-Package: com.sun.jna,
 com.sun.jna.ptr,
 com.sun.jna.win32
Export-Package: com.foo.bar
Bundle-NativeCode: foo.dll;
 osname=WindowsXP;
 processor=x86
然后在我的JNA接口中执行loadLibrary(根据文档):

然后在另一个类中,我尝试使用JNA接口

// ...code
int var = MyFooInterface.INSTANCE.bar();
// ...more code
我通过另一个bundle(导出com.sun.JNA和上面导入的其他包)提供了JNA,但也尝试使用这里定义的bundle对其进行打包(在这种情况下,将其添加到类路径中,等等)

我还尝试指定
Bundle NativeCode:/foo.dll

同样有趣的是,这些是相关的OSGi属性(我使用
getprop

即使在所有这些之后(以及在我进行的每一次尝试中),我总是会出现以下错误(并且没有显示堆栈跟踪):

…那么我错过了什么

编辑:我还应该注意,我已经测试了JNA接口代码和作为JUnit测试程序一部分与之对话的DLL,并取得了成功

编辑2:将此代码添加到调用库的类中似乎允许JNA查找库(稍后调用
Native.loadLibrary
时)。基于清单中的Bundle NativeCode指令,我似乎应该能够避免这个调用。显然,一旦加载了库,Native.loadLibrary就会抓住它的现有实例,但我不希望依赖这种特定于顺序的策略

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

我建议您尝试将dll打包为jar:

jar cvf foo.dll.jar foo.dll

并将jar作为常规库加载。

查看JNA的文档,它指出:

  • 使目标库可用于Java程序。有两种方法可以做到这一点:
    • 首选方法是将
      jna.library.path
      系统属性设置为目标库的路径。此属性类似于
      java.library.path
      ,但仅适用于JNA加载的库
    • 在启动VM之前,请更改相应的库访问环境变量。这是Windows上的
      PATH
      ,Linux上的
      LD\u LIBRARY\u PATH
      ,OSX上的
      DYLD\u LIBRARY\u PATH
因此,为了克服这个缺点,您可以解析库的绝对路径并加载它


假设它是Eclipse的标准类加载器,您可以执行
ClassLoader.findLibrary()
,它应该在包中找到本地库。

问题在于专门的JNA loadLibrary调用,它不支持OSGi。当您从OSGi捆绑包调用loadLibrary时,它将使用OSGi类加载器(该类加载器可识别捆绑包)查找DLL所在的位置,在本例中,将其从捆绑包中提取出来,并通过System.loadLibrary()调用针对特定位置使其可加载

既然这个JNA看起来(a)不支持OSGi,而且(b)是超级库,为什么不直接使用System.loadLibrary()呢


如果您需要同时编写这两个文件,那么在BundleActivator的bundle的start()方法中执行System.loadLibrary(),这将引入本机库(您可能希望确保如果无法加载,则无论如何都无法启动该bundle)。

我不确定这是一种可行的方法,我需要将DLL作为本机库加载,我已经确定它是作为试图使用它的OSGi包的一部分打包的。jvm可以在Jarso FWIW中找到本机lib,我试过了,但没有效果。我构造了foo.jar并将其添加到我的类路径中(这会将行:Bundle ClassPath:libs/foo.jar,)添加到上面的清单中,但仍然找不到库。问题不仅仅源于JVM无法看到它,还需要通过OSGi路径/类加载器加载它。您使用的是哪个OSGi实现?我使用的是Equinox(规范R4)您可能需要说明您使用的是哪个版本的Java,因为我以前从未见过JNA,而且它在6之前(包括6)都不是Java的一部分。System.loadLibrary()调用有效,因为它将调用类加载器的findLibrary()方法,如果它是类加载器的Eclipse实现,将通过查看捆绑包内部找到“本地”库。当您遇到这些严重问题时,不要害怕调试这些类加载器和系统调用,这可能非常有教育意义。最终,JNA必须调用自己的Native.loadLibrary或Native.register(使用调试器跟踪后,遵循相同的事件序列)为了启用JNA提供的接口驱动或直接本机访问。我发现解决方案(尽管看起来不太令人满意)是首先调用System.loadLibrary,正如您所建议的,然后在适当的位置调用Native.loadLibrary或Native.register。您可能会发现这在Windows上有效,但在其他平台上可能不起作用。我记得一个问题,即加载一个具有依赖项的DLL在Windows上工作(当B依赖于a时,先加载a,然后加载B),但在Mac上有问题。我不知道为什么会这样。。。但这只是一个警告,说明您手中可能有一个特定于平台的解决方案。至少,您应该测试(而不是假设)非Windows平台。System.loadLibrary使用OSGi类加载器——为了定位DLL,清单中的Bundle NativeCode语句是绝对必需的——因此,无论操作系统如何,此解决方案都会找到本机代码。如果foo.dll依赖于bar.dll,则按顺序加载它们将变得非常重要,但这是另一个问题,幸运的是,这里的情况并非如此。不过,谢谢你的提醒。我也遇到了同样的问题,并找到了解决办法。正如JNA文档所述,“在路径
{OS}-{ARCH}/{library}
下,使本机库在类路径上可用,wh
java.lang.UnsatisfiedLinkError: Unable to load library 'foo': The specified module could not be found.
static{
    System.loadLibrary("foo");
}
jar cvf foo.dll.jar foo.dll