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


Je prolonge les guices AbstractModule et à l'intérieur de la classe en extension, j'ai besoin d'accéder à l'injecteur de Guice. C'est possible, si oui, comment?


23
2018-04-13 16:21


origine


Réponses:


Ceci est une demande inhabituelle. Les modules ressemblent plus à des fichiers de configuration qu'à des fichiers logiques: le module est lu pour créer l'injecteur, et 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 éliminé.

Dans tous les cas, plutôt que de demander à un injecteur d’obtenir la classe X, vous devez 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 valables nécessitant l'accès à un injecteur depuis un module:

Dans un @Provides méthode:

Les modules peuvent contenir des mini-fournisseurs dans méthodes annotées avec @Provides. Rappelez-vous que Injector est injectable: Si vous avez besoin d'un injecteur dans l'une de ces méthodes, vous pouvez simplement l'accepter en tant que 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, si vous obtenez une erreur si vous appelez get() sur ce fournisseur avant que l'injecteur ne soit prêt à le fournir (par exemple 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 voulez.

Pour obtenir une instance dans votre configure ():

C'est une mauvaise idée; Guice n'est pas prêt à fournir des instances tant que toutes les méthodes de configuration ne sont pas exécutées. Le plus proche que vous pouvez obtenir est de créer un injecteur enfant utiliser les autres modules et le transmettre à 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);
  }
}

44
2018-04-13 18:49