Кто-нибудь использовал 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 = механизм плагина