Используйте аннотацию для подачи Google Guice MapBinder - PullRequest
0 голосов
/ 27 февраля 2019

В проекте Java, сборка с Gradle 5.2, с использованием Google Guice.

Я использую MapBinder (http://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/multibindings/MapBinder.html):

MapBinder<String, Snack> mapbinder
         = MapBinder.newMapBinder(binder(), String.class, Snack.class);
     mapbinder.addBinding("twix").toInstance(new Twix());
     mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
     mapbinder.addBinding("skittles").to(Skittles.class);

Это работает нормально, но сейчас,Я хочу "архитектуру плагинов", поэтому избегайте импорта всех классов Snack, а скорее объявляйте ее непосредственно в классе, например:

@SnackImpl("Twix")
class Twix extends Snack {

}

Как?

1 Ответ

0 голосов
/ 28 февраля 2019

Это не будет возможно без дорогостоящего сканирования пути к классам: если у инжектора нет ссылок на ваш класс Twix, он не сможет связать его с картой без сканирования через каждый JAR на пути к классам впоиск @SnackImpl -аннотированных классов.Вы можете попробовать это с ClassPath Guava , но если вы используете сетевой или пользовательский загрузчик классов, это может вообще не быть отслеживаемым.В любом случае я бы не рекомендовал это делать.

Одной из альтернатив является использование встроенной в Java инфраструктуры ServiceLoader , которая позволяет отдельным JAR-файлам перечислять полностью определенные реализации для данной службы (интерфейс).Вы даже можете использовать Google Framework для генерации этого сервисного файла для вас на основе аннотаций.

Это поможет составить список реализаций, но вам все равно нужно будет связать их в MapBinder.,К счастью, MapBinder не требует одного определения и автоматически объединит несколько определений MapBinder во время создания модуля:

Поддерживается добавление привязок карт из разных модулей.Например, нормально, чтобы CandyModule и ChipsModule создавали свои собственные MapBinder, и каждый из них вносил привязки в карту закусок.Когда эта карта внедряется, она будет содержать записи из обоих модулей.

(из Документы MapBinder )

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

// Assume CandyPluginModule extends AbstractModule

@AutoService(CandyPluginModule.class)
public TwixPluginModule extends CandyPluginModule {
  @Override public void configure() {
    MapBinder<String, Snack> mapBinder
       = MapBinder.newMapBinder(binder(), String.class, Snack.class);
    mapBinder.addBinding("twix").to(Twix.class);
  }
}

Вы также можете взятьПреимущество суперкласса:

@AutoService(CandyPluginModule.class)
public TwixPluginModule extends CandyPluginModule {
  @Override public void configureSnacks() {  // defined on CandyPluginModule
    bindSnack("twix").to(Twix.class);
  }
}

В качестве альтернативы, вы можете перечислить реализации, такие как Twix, непосредственно с AutoService, а затем создать Модуль, который считывает все реализации ServiceLoader в MapBinder, но это может ограничить гибкость ваших плагинов.и не получает никакой децентрализации привязок, которые MapBinder уже не дает.

...