Доступ к инжектору Guice в его модуле?

Я расширяю Guice AbstractModule и внутри расширяющегося класса мне нужен доступ к инжектору Гизе. Это возможно, если да, то как?

Ответ 1

Это необычный запрос. Модули больше похожи на файлы конфигурации, чем на логические файлы. Модуль читается для создания Инжектора, а затем, как только инжектор создается, модуль выполнил свою работу. Для простого модуля инжектор буквально не существует, пока модуль не будет готов к отбрасыванию.

В любом случае, вместо того, чтобы запрашивать инжектор для получения класса X, вы обычно должны запрашивать Provider<X>. Guice будет введите X или Provider<X> для привязки X, Provider<X> или @Provides X, поэтому вы почти всегда можете это сделать. Тем не менее, инъекция инжектора позволит вам получить экземпляр рефлексивно или проверить привязки инжектора (и т.д.).

Вот несколько веских причин/конструкций, которые требуют доступа к инжектору из модуля:

В методе @Provides:

Модули могут содержать мини-провайдеров в методах, аннотированных с помощью @Provides. Помните, что Injector используется для инъекций: если вам нужен инжектор в одном из этих методов, вы можете просто принимайте его как параметр:

public class OneModule extends AbstractModule {
  @Override public void configure() { /* ... */ }

  @Provides YourDependency getYourDependency(Injector injector) {
    return injector.getInstance(Class.forName(yourDependencyName));
  }

  @Provides Something getSomething(SomethingImpl something) {
    return initialize(something); // preferred: only ask for what you need
  }

  @Provides SomethingElse getSomethingElse(Provider<Thing> thingProvider) {
    return new SomethingElse(thingProvider); // asking for a provider works too
  }
}

Чтобы получить поставщика в вашем configure():

AbstractModules выставляют getProvider() именно по этой причине, хотя вы получите сообщение об ошибке, если вы вызываете get() этого Провайдера до инжектор готов предоставить его (например, во время настройки):

public class TwoModule extends AbstractModule {
  @Override public void configure() {
    bind(Thingy.class).toInstance(
        new MyThingy(8675309, getProvider(Another.class)));
  }
}

Возможно, вы можете позвонить getProvider(Injector.class), но я не знаю, работает ли это, и я не знаю, почему вы хотите.

Чтобы получить экземпляр в вашем configure():

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

public class MainClass {
  public static void main(String[] args) {
    Injector firstStage =
        Guice.createInjector(new OtherModule1(), new OtherModule2());
    // An alternative design would @Inject-annotate fields in ThreeModule
    // and get it from firstStage, but that nonstandard and may be confusing.
    Injector secondStage =
        firstStage.createChildInjector(new ThreeModule(firstStage));
  }
}

public class ThreeModule extends AbstractModule {
  private final Injector otherInjector;

  public ThreeModule(Injector otherInjector) { 
    this.otherInjector = otherInjector;
  }

  @Override public void configure() {
    bindStuffBasedOn(otherInjector);
  }
}