java.util.ServiceLoader не загружает мой класс провайдера

Я пытаюсь собрать базовый реестр обработчиков на основе 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, который реализует этот интерфейс. Я создал файл в моем банке с именем META-INF/services/com.example.handler.Handler, который содержит одну строку

com.example.handler.handlers.DummyHandler

в соответствии с Javadoc. Мой модульный тест просто вызывает метод lookup() для проверки поиска обработчика для элемента. Конечно, в конечном итоге потребуется какая-то проверка, чтобы убедиться, что это правильный обработчик для этого элемента, но на данный момент я даже не вижу, как мой класс DummyHandler загружается реестром. Я что-то здесь не так делаю?

Спасибо!

1 ответ

Ответ, похоже, заключается в чувствительности к тому, как именно это настроено. Я поместил файл ресурса имени своего провайдера (файл с именем com.example.handler.Handler) непосредственно в каталог проекта верхнего уровня, т.е. /resources/META-INF/services/com.example.handler.Handler. Я настроил свой build.gradle, чтобы вытащить файл и положить его в банку:

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

Когда я проверил файл фляги, файл был там, где я и ожидал, поэтому я подумал, что все в порядке. При удачном стечении обстоятельств я случайно переместил папку ресурсов из папки src/main и presto! оно работает. Я проверил файл jar, и он кажется идентичным тому, который был создан предыдущим способом, но по какой-то причине этот работает. Я буду обновлять дальше, если смогу определить разницу, но, по крайней мере, мой тестовый пример работает сейчас.

Другие вопросы по тегам