Есть ли способ получить доступ к инжекторам Guice, которые были созданы ранее? - PullRequest
0 голосов
/ 10 января 2020

Взгляните на Guice (и Dagger) для нового проекта. В каждом уроке Guice, который я видел до сих пор, показан инжектор, созданный в точке, где разработчику нужен DI для создания экземпляра объекта.

Типичный пример, видимый в Интернете:

public static void main(String[] args) {
    Injector injector = Guice.createInjector(new BasicModule());
    Communication comms = injector.getInstance(Communication.class);
}

Для меня это противоречит цели DI - везде, где требуется экземпляр, вы ie экземпляра для модулей, которые определяют, как его создать.

Есть ли способ попросить Guice создать экземпляр класса who, модуль (граф зависимостей) которого был ранее определен для Guice (например, при запуске приложения?).

Я использую фреймворк Dropwizard.io, поэтому бывают ситуации, когда у меня нет полного контроля над созданием класса, но я хочу иметь возможность смоделировать зависимости, на которые я ссылаюсь в этом классе.

Точно то же самое относится и к Dagger - я буду признателен за примеры для обоих / *. 1012 *

Редактировать: Я работал с несколькими DI-фреймворками в. NET более годы, поэтому я собираюсь привести пример того, что я пытаюсь сделать, основываясь на одном из них.

Например, в реализации ASP. NET Core DI, на службе При запуске вы определяете сервисы, которые вы хотите, чтобы DI мог создавать. Обычно вы будете просить DI дать вам экземпляр, который является реализацией интерфейса. Итак, при запуске:

protected override void ConfigureAdditionalServices(IServiceCollection services)
{
    services.AddScoped<ITransactionService, TransactionService>();
}

, где IServiceCollection - это набор служб, определенных для DI.

Поскольку DI интегрирован с каркасом ASP. NET с этого момента вы обычно можете определить конструктор, который принимает ITransactionService, и DI предоставит его вам.

Однако, если вы использовали DI в платформе, которая не знала об этом, вам понадобился бы доступ к текущему экземпляру ServiceProvider, а затем вы могли бы попросить DI создать ваш объект следующим образом:

var transactionService = ServiceProvider.GetService<ITransactionService>();

Я понимаю, что это реализует антишаблон Service Locator , но он по-прежнему имеет то преимущество, что отсоединяет мой код от реализаций конкретного класса и позволяет мне макетировать их для тестирования в запуск приложения.

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

Что мне нужно изменить в этом коде, чтобы он работал?

public class TransactionModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(TransactionServiceBase.class).to(TransactionService.class);
  }
}

// At startup
Injector injector = Guice.createInjector(new TransactionModule());


// Then, somewhere in the application, to get an instance of TransactionService
TransactionServiceBase transactionService = (TransactionServiceBase)Guice.getInstance(TransactionServiceBase.class);

Ответы [ 2 ]

0 голосов
/ 14 января 2020

Я думаю, что ответ заключается в том, что не существует стандартного / поддерживаемого способа сделать это.

Обычные предположения состоят в том, что у вас есть как можно меньше «инъекционных» точек, в идеале одна, и затем вы указываете что нужно каждому классу путем создания аргументов конструктора зависимостей.

Единственный известный мне сценарий, похожий на описанный здесь, - это Dagger в android приложениях. Они решили, что они хранят кинжал «Инжектор» (sorta) в глобальном объекте - приложении, а затем Dagger предоставляет функцию stati c для извлечения этого объекта и выполнения инъекций.

Короче говоря, DI-фреймворки плохо работают с парадигмами, в которых вы сами не создаете экземпляры классов.

И единственное решение, которое я могу придумать, - это сохранить ваш инжектор в некоторой глобальной переменной и получить его оттуда, когда вам это нужно.

Stati c инъекция может в некоторой степени помочь в вашем кейс https://github.com/google/guice/wiki/Injections#static -инъекции

0 голосов
/ 10 января 2020

Я думаю, что вы, возможно, неправильно понимаете Injector.getInstance - так же, как в вашем примере есть метод public static для начала, даже если вы обычно не пишете остальную часть своего приложения со всеми публикациями c stati c методов (я надеюсь), вы также не вызываете Injector.getInstance, за исключением очень немногих конкретных c случаев.

Вместо этого этот код используется только для того, чтобы все заработало. Еще одно популярное «начало работы» - это injector.injectMembers(this) - пусть main() создает экземпляр вручную из того, что является основой вашего приложения, с @Inject -отмеченными членами, а затем просто просит только что созданный Injector заполнить члены.

Если вы продолжите "внутрь" к остальной части вашего приложения, вы , вероятно, никогда не будете ссылаться на экземпляр Injector снова, а вместо этого будете полагаться на провайдеров, ассистированную инъекцию или просто подсказку. созданные экземпляры.

Таким образом, вы никогда не должны заботиться об инжекторе или точных модулях, которые были для него установлены. Только один Инжектор должен существовать на протяжении всего жизненного цикла приложения (к этому нет никаких исключений, за исключением, может быть, если вы переопределите, что такое «приложение»), и в 99% случаев оно скрыто от вас (исключения: где ваш DI соответствует некоторому другому DI, и ему необходимо запросить экземпляр чего-либо по его классу, или если у вас есть инструментальные средства, которые хотят проанализировать набор всех объявленных привязок). Таким образом, вы должны иметь возможность просто предоставлять сеттеры, аргументы конструктора или методы init, а затем можете вызывать их вручную или иметь любой контекстный контекст, создавая их на основе своих собственных указанных c модулей и правил.

...