Кто-нибудь использовал ServiceLoader вместе с Guice?

Я все еще хочу попробовать это в более широком масштабе с помощью нашей системы app + build, но более высокие приоритеты продолжают подталкивать ее на задний план. Похоже, это хороший способ загрузить модули Guice и избежать общей жалобы на "жестко закодированную конфигурацию". Индивидуальные свойства конфигурации редко меняются сами по себе, но вы почти всегда будете иметь набор профилей, как правило, для разных сред (Debug, Production и т.д.).

ServiceLoader позволяет вам отображать список всех реализаций, определенных как служба для определенного типа. Помещая это вместе с Guice, вы получите:

import java.util.ServiceLoader;

import com.google.inject.AbstractModule;
import com.google.inject.Module;

public class ModuleLoader<M extends Module> extends AbstractModule {

    private final Class<M> type;

    public ModuleLoader(Class<M> type) {
        this.type = type;
    }

    public static <M extends Module> ModuleLoader<M> of(Class<M> type) {
        return new ModuleLoader<M>(type);
    }

    @Override
    protected void configure() {
        ServiceLoader<M> modules = ServiceLoader.load(type);
        for (Module module : modules) {
            install(module);
        }
    }
}

Пример использования (в качестве динамического загрузчика сервлетов в проекте guice-servlet):

import com.google.inject.servlet.ServletModule;

public class ServletLoader extends GuiceServletContextListener {
    @Override
    protected final Injector getInjector() {
       return Guice.createInjector(ModuleLoader.of(ServletModule.class);
    }
}

Службы (упакованные как модули) будут упакованы в отдельные файлы jar. Внутри каждого из них вы определяете класс в метаданных:

Within servlets.jar: META-INF/services/com.google.inject.Module

com.example.webapps.MyServletModuleA
com.example.webapps.MyServletModuleB

Поскольку мы используем Maven, мы считаем, что это было бы идеально, поскольку мы могли бы использовать различные реализации во время выполнения через зависимости профиля. Кто-нибудь использует Guice вот так?

Если нет, не стесняйтесь использовать этот пример и посмотреть, как он работает для вас. (ServiceLoader поддерживается только в JDK6 +)

Ответы

Ответ 1

Мы делаем почти что именно на моей работе. Мы в настоящее время застряли в java 5 из-за некоторых внутренних ограничений, поэтому мы делаем это по-другому, используя Service Provider (из-за отсутствия доступа к ServiceLocator до java 6, как вы упомянули), но он по сути работает одинаково.

Я помню, где-то читал, что это был один из предпочтительных способов, рекомендованных разработчиками Guice, хотя они хотят оставить это открытым для гибкости.

Ответ 2

Я уже рассматривал этот путь, но я не использовал его, потому что я боялся, что мне нужно, чтобы мои модули были очень маленькими, потому что его невозможно связать один и тот же интерфейс дважды. Моя проблема заключается в том, что если я хочу использовать интерфейс/класс/enum/any из другой банки, и этот jar определил файл services/*, который я напортачил, потому что я не могу использовать содержимое банки, не загружая ее как модуль.

Надеюсь, моя озабоченность будет ясна.

Ответ 3

", потому что его невозможно связать один и тот же интерфейс дважды.

Это действительно неправильно! С Guice Multibinder существует способ работать с различными реализациями одного и того же интерфейса, возможно, связанным в разных модулях.

Я пришел к немного другому решению для фактической загрузки, чем Марк Ренуф (его ModuleLoader выглядит действительно лучше), но мой пост в блоге может показать немного больше об окружающей среде, в которой этот подход применим (плагины) и какие точки расширения выглядят так:

Guice 2.0 Multibinder + Java ServiceLoader = механизм плагина