【问题标题】:java.util.ServiceLoader not loading my provider classjava.util.ServiceLoader 未加载我的提供程序类
【发布时间】:2013-08-07 13:46:20
【问题描述】:

我正在尝试整理一个基本的基于 SPI 的处理程序注册表,我从 HandlerRegistry 中查找它。当我使用 ServiceLoader.load(Handler.class) 初始化提供程序,然后迭代列表以延迟加载它们时,我没有看到该类的任何实例。保持这个尽可能简单,我的 HandlerRegistry 类是:

public class HandlerRegistry 
{
  private static HandlerRegistry registry;

  private ServiceLoader<Handler> handlerLoader;

  private HandlerRegistry()
  {
    handlerLoader = ServiceLoader.load(Handler.class);
  }

  public static synchronized HandlerRegistry getRegistry()
  {
    if (registry == null) {
      registry = new HandlerRegistry();
      registry.init();
    }
    return registry;
  }

  private void init()
  {
System.out.println("HandlerRegistry.init()");
  }

  public Handler lookup(String item)
  {
System.out.println("lookup("+item+")");
    try {
      Iterator<Handler> it = handlerLoader.iterator();
      while (it.hasNext()) {
        Handler handler = it.next();
System.out.println("found handler "+handler);
      }
    }
    catch (ServiceConfigurationError err) {
      err.printStackTrace();
    }
    return null;
  }
}

我有一个 com.example.handler.Handler 接口(为简单起见暂时为空),以及一个实现该接口的 com.example.handler.handlers.DummyHandler 类。我在我的 jar 中创建了一个名为 META-INF/services/com.example.handler.Handler 的文件,其中包含一行

com.example.handler.handlers.DummyHandler

根据 javadoc。我的单元测试只是调用lookup() 方法来验证查找处理程序的项目。当然,最终需要进行某种检查以查看这是否是该项目的正确处理程序,但此时我什至没有看到我的 DummyHandler 类被注册表加载。我在这里做错了吗?

谢谢!

【问题讨论】:

    标签: java serviceloader


    【解决方案1】:

    答案似乎在于对它的确切配置方式的敏感性。我一直将我的提供者名称资源文件(名为 com.example.handler.Handler 的文件)直接放在顶级项目目录中,即 /resources/META-INF/services/com.example.handler.Handler。我已将 build.gradle 配置为将文件拉出并放入 jar 中:

    jar { from('resources') { include 'META-INF/services/*.*' } }
    

    当我检查 jar 文件时,文件就在那里,就在我预期的位置,所以我认为一切都很好。在踢球时,我碰巧将资源文件夹从 src/main 下移动了下来,然后!有用。我检查了 jar 文件,它看起来与以前的方式构建的相同,但由于某种原因,这个可行。如果我能确定差异,我会进一步更新,但至少我的测试用例现在可以工作了。

    【讨论】:

    • 另一个关键是确保使用 UTF-8 编码没有资源文件的字节顺序标记。包含 BOM 时,它会被解释为类名的一部分并导致构建问题。
    • 万一其他人重新访问这个,我让它在一个 Java 项目中工作,但如果我将它捆绑在一个实用程序 jar 中并尝试在另一个项目中使用它,java.nio.Files#probeContentType() 找不到我对java.nio.file.spi.FileTypeDetector 的实现。服务提供者开始寻找我的META-INF/java.nio.file.spi.FileTypeDetector 服务实现列表,但没有找到。
    • 嗨@bachman,我遇到了同样的问题。我有一个提供者(超类),并且有三个子类。一个来自axis2-jaxws jar,第二个来自jdk的rt.jar,第三个来自jaxws-rt.jar。我想要来自axis2-jaxws.jar 的孩子,但ServideLoader 正在返回来自jaxws-rt.jar 的孩子。当我删除 jaxws-rt.jar 时,一切正常。但我不确定这是否是个好主意,因为 SOAP Web 服务仅在运行时需要一些 jar。你或任何人都记得这个问题的解决方案吗?
    猜你喜欢
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多