Кто-нибудь использовал ServiceLoader вместе с Guice? - PullRequest
14 голосов
/ 24 мая 2009

Я все еще хочу попробовать это в большем масштабе с нашей системой 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 +)

Ответы [ 3 ]

3 голосов
/ 08 августа 2009

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

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

1 голос
/ 16 января 2010

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

Я надеюсь, что мое беспокойство ясно.

0 голосов
/ 27 января 2011

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

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

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

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

...