3

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

我有一个 interface.jar,它声明了接口。我有 implementations.jar,它有这个接口的几个实现,都在 spi/META-INF/services/my.package.name.MyInteface 文件中指定(这个文件在implementations.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、implementations.jar 和 handler.jar 是在 Eclipse 中创建的,它们是另一个应用程序的一部分。

在 NetBeans 中,我打开了需要使用新实现的模块,并将所有 3 个 jars 添加为外部库(NetBeans 将它们复制到它的 ext 文件夹中,我不想要,但我无能为力 - 我希望它们在另一个 myext 文件夹中,但那是另一回事)。然后我重建了所有东西并尝试使用我的一个实现,但没有找到......获取实现的代码在 ImplementationHandler 类中,如下所示:

public static final <T> MyInteface<T> getByName(String name) {
    for (MyInteface implementation : loadAllImplementations()) {
        if (implementation.getName().equals(name)) {
            return implementation;
        }
    }

    throw new IllegalArgumentException("Unable to find MyInterface class for: " + name);
}

我得到了我的异常“无法找到 MyInteface 类:myImplementationName”...

我对 NetBeans 的了解非常有限,我想知道我还需要做些什么才能使其正常工作吗?

4

3 回答 3

2

为了工作,您必须让 Netbeans 在 META-INF 中创建此服务子文件夹。这很容易做到,但信息很容易获得。

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

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

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

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

于 2011-07-06T13:47:49.197 回答
0

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

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

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

最有可能的是,handler.jar 和 implementations.jar 不是由同一个类加载器加载的。此外,您可能想看看为什么您的文件会进入 ext 文件夹。

希望这可以帮助。

编辑:

  • 还尝试调用ServiceLoader.load(Class, null)使用 System 类加载器(启动应用程序的类加载器)。可能该类加载器可能能够在 ext 目录中的 jar 中找到类。
于 2010-07-02T14:40:08.807 回答
0

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

于 2010-07-12T12:52:37.793 回答