web-dev-qa-db-fra.com

Accéder à l'injecteur Guice dans son module?

J'étends AbstractModule de Guice et à l'intérieur de la classe d'extension j'ai besoin d'accéder à l'injecteur de Guice. Est-ce possible, si oui, comment?

33
stefan.at.wpf

Il s'agit d'une demande inhabituelle. Les modules ressemblent plus à des fichiers de configuration qu'à des fichiers logiques: le module est lu pour créer l'injecteur, puis dès que l'injecteur est créé, le module a fait son travail. Pour un module simple, l'injecteur n'existe littéralement que lorsque le module est prêt à être jeté.

Dans tous les cas, plutôt que de demander un injecteur pour obtenir la classe X, vous devriez généralement demander un Provider<X>. Guice va injecter un X ou Provider<X> Pour toute liaison de X, Provider<X>, Ou @Provides X , vous pouvez donc presque toujours le faire à la place. Cela dit, l'injection de l'injecteur vous permettra d'obtenir une instance de manière réfléchie ou d'inspecter les liaisons de l'injecteur (etc.).

Voici quelques raisons/conceptions valides qui nécessiteraient d'accéder à un injecteur à partir d'un module:

Dans une méthode @Provides:

Les modules peuvent contenir des mini-fournisseurs dans méthodes annotées avec @Provides . N'oubliez pas que Injector est injectable : Si vous avez besoin d'un injecteur dans l'une de ces méthodes, vous pouvez simplement l'accepter comme paramètre:

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
  }
}

Pour obtenir un fournisseur dans votre configure ():

AbstractModules expose getProvider() pour exactement cette raison, mais vous obtiendrez une erreur si vous appelez get() sur ce fournisseur avant que l'injecteur ne soit prêt à le fournir ( comme au moment de la configuration):

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

Vous pouvez probablement appeler getProvider(Injector.class) mais je ne sais pas si cela fonctionne et je ne sais pas pourquoi vous le souhaitez.

Pour obtenir une instance dans votre configure ():

C'est une mauvaise idée; Guice n'est prêt à fournir des instances qu'après l'exécution de toutes les méthodes de configuration. Le plus proche que vous pouvez obtenir est de créer un injecteur enfant en utilisant les autres modules et le passer dans ce module, mais même cela est rarement nécessaire.

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's 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);
  }
}
51
Jeff Bowman