【问题标题】:How to make the java ServiceLoader work in a NetBeans 6.9 module application如何使 java ServiceLoader 在 NetBeans 6.9 模块应用程序中工作
【发布时间】:2023-04-11 04:35:01
【问题描述】:

我在 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 文件夹中,我不想要,但我无能为力about - 我希望它们在另一个 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 的了解非常有限,我想知道我还需要做些什么才能使其正常工作吗?

【问题讨论】:

  • “spi/META-INF/services/”中的“spi”是错字吗? META-INF 文件夹应该在类路径的根目录中。
  • 是的,对不起,我粘贴了“源”路径,该文件是从构建脚本中获取的。我检查了一下,它位于罐子的根部。如果它不存在,它也不应该在 Eclipse 中工作:)

标签: java netbeans serviceloader


【解决方案1】:

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

    您可能需要为此尝试不同的方法:

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

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

    希望这会有所帮助。

    编辑:

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

    【讨论】:

    • 您好,感谢您的回答!我将首先尝试 System 类加载器。 jar 应该在 netbeans 模块类路径中,因为我将它们作为库添加到将使用它们的模块而不是整个项目中。我认为默认情况下,您的 jars 会进入 ext 文件夹,我认为这并不重要,因为 netbeans 会自动生成这个 Class-Path manifest 属性,正如您所描述的。我检查了这个属性,它正确指向了 ext 文件夹中的所有 jar,并且这些 jar 都在那里。
    • 系统类加载器也看不到它们 :(
    • 可能是@Jörn Horstmann 的评论可能有一些线索?关于 spi 目录? META-INF 目录是否在 jar 的根目录下?最后的手段是尝试 URLClassLoader 方法。
    • 是的,它在根目录中。 URLClasLoader 方法可能真的是最后的手段……我明天试试
    • 我发现这个模块在代码中使用了一些自定义类加载器,里面有像“resolveHiddenClasspath”这样的神奇方法......我想我应该深入研究那个模块的来源以获得线索发生了什么
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-04
      • 1970-01-01
      相关资源
      最近更新 更多