如何使java ServiceLoader在NetBeans 6.9模块应用程序中工作

我在NetBeans模块应用程序中使用java ServiceLoader时遇到了麻烦。 这是我正在尝试做的(它在Eclipse中的普通java应用程序中工作):

我有一个interface.jar,它声明了接口。 我有implements.jar,它有几个这个接口的实现,都在spi / META-INF / services / my.package.name.MyInteface文件中指定(这个文件位于implementation.jar中)。

我还有一个类ImplementationHandler(在另一个handler.jar中),它有以下方法来加载所有实现:

private static List<MyInterface> loadAllImplementations() { List<MyInterface> foundImplementations = Lists.newArrayList(); try { for (MyInterface implementation : ServiceLoader.load(MyInterface.class)) { foundImplementations.add(implementation); } } catch (ServiceConfigurationError error) { system.out.println("Exception happened"); } return foundImplementations; } 

此代码返回Eclipse正常应用程序中的所有实现(foundImplementations.size()> 0)。

但是在NetBeans下,它找不到任何内容(foundImplementations.size()== 0)。

更多细节:
我有一个NetBeans模块应用程序的源代码(开源,不是我编写的),我需要通过使用一些MyInterface实现来扩展它。 interface.jar,implements.jar和handler.jar是在Eclipse中创建的,它们是另一个应用程序的一部分。

在NetBeans中,我打开了需要使用新function的模块,我将所有3个jars添加为外部库(NetBeans将它们复制到其ext文件夹中,我不想要但我无法做任何事情 – 我想要他们在另一个myext文件夹中,但这是另一个故事)。 然后我重新构建了所有内容并尝试使用我的一个实现,但是没有找到…获得实现的代码在ImplementationHandler类中,看起来像:

 public static final  MyInteface getByName(String name) { for (MyInteface implementation : loadAllImplementations()) { if (implementation.getName().equals(name)) { return implementation; } } throw new IllegalArgumentException("Unable to find MyInterface class for: " + name); } 

我得到了exception“无法找到myInteface类:myImplementationName”…

我对NetBeans的了解非常有限,我想知道为了实现这个目标,我还需要做些什么吗?

为了工作,您必须使Netbeans在META-INF中创建此服务子文件夹。 这很容易,但信息很容易访问。

要向META-INF添加内容,您需要在src /(源目录[spi?])文件夹中创建此名称的文件夹。 在这种情况下,您还需要services文件夹,并在其中创建一个与服务接口具有相同完全限定名称的文本文件。 最后你应该有这个结构:src / META-INF / services / my.package.MyInterface。

最后,这个[my.package.MyInterface]文件的内容应列出所有实现类(每行一个)。

通过此设置,Netbeans将在构建应用程序时创建相应的jar。

看一下这个ServiceLoader示例。 这是一个完整的例子,虽然它没有解释我刚刚描述的Netbeans集成。

ServiceLoader.load(Class)使用当前线程的上下文类加载器来加载所有实现。 在您的情况下,您的jar文件(implementation.jar)中的实现类可能不在该类加载器的类路径中。

您可能必须尝试不同的方法:

  • 您可能需要在netbeans模块的类路径中包含所有jar,或者,
  • 您可能需要创建一个类加载器(可能是在其类路径中具有这些jar的URLClassLoader)并使用ServiceLoader.load(Class, ClassLoader)并传递ServiceLoader.load(Class, ClassLoader)加载器。
  • 您可以尝试另一种选择,但我不确定:jar文件规范允许您指定Class-Path清单属性,您可以在其中添加“implementation.jar”条目。 更多细节在这里

最有可能的是,handler.jar和implements.jar不是由同一个类加载器加载的。 您还可以查看文件进入ext文件夹的原因。

希望这可以帮助。

编辑:

  • 还尝试调用ServiceLoader.load(Class, null) ,它使用System类加载器(启动应用程序的加载器)。 可能类加载器可能能够在ext目录中的jar中找到类。

我放弃了,用JSPF替换了ClassLoader。 这开箱即用,我不需要知道第三方程序的内部结构,编写为NetBeans模块,以及它如何影响类加载器的类路径。