在其模块中访问 Guice 喷油器?

Accessing Guice injector in its Module?

提问人:stefan.at.kotlin 提问时间:4/14/2013 最后编辑:CraigTeegardenstefan.at.kotlin 更新时间:7/9/2020 访问量:42621

问:

我正在扩展 Guice,在扩展类中,我需要访问 Guice 的喷油器。如果是,可能,如何?AbstractModule

Java 依赖注入 guice

评论


答:

64赞 Jeff Bowman 4/14/2013 #1

这是一个不寻常的请求。模块更像是配置文件,而不是逻辑文件:读取模块以创建 Injector,然后在 Injector 创建后,模块就完成了它的工作。对于一个简单的模块,在模块准备好被丢弃之前,注入器实际上并不存在。

在任何情况下,您通常都应该请求 .Guice 将为 X、Provider<X> 或 @Provides X 的任何绑定注入 X 或 Provider< X>因此您几乎总是可以这样做。也就是说,注入 Injector 将允许您反射性地获取实例,或检查 Injector 的绑定(等)。Provider<X>

以下是一些需要从模块内访问喷油器的有效原因/设计:

在方法中:@Provides

模块可以在@Provides 注释的方法中包含微型提供程序。请记住,Injector 是可注射的:如果您需要其中一种方法的 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() 中获取 Provider:

正是出于这个原因,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 还没有准备好提供实例。最接近的方法是使用其他模块创建一个子 Injector 并将其传递到此模块中,但即使这样也很少需要。

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

评论

2赞 ilikeorangutans 4/16/2013
我同意,这是一个不寻常的要求,可能暗示着设计的味道。
0赞 leozilla 2/16/2017
AbstractModule#configure() 中的 getProvider() 方法是要走的路
11赞 Line 1/16/2018
@ilikeorangutans喜欢这样的评论;他们总是让我觉得我的设计很臭,但不知道如何改进它:D
1赞 Ferran Maylinch 7/9/2020
虽然不寻常,但我不认为这总是一个糟糕的设计,哈哈。我们有一个场景,我们希望从其类中动态获取一个实例。当您接近动态场景(反射等)时,您开始需要高级“元”功能。
0赞 Jeff Bowman 7/22/2020
@FerranMaylinch 为自己说话:我的反对意见与动态访问或使用喷油器无关。当然,在可能的情况下,明确你的依赖关系是有意义的,并尽可能减少使用Guice特定的组件,但通过Injector进行反射访问是Guice的一个很好的用例。我的建议更多的是明确区分“配置时”和“运行时”:你对 Injector 的使用应该在类而不是模块中(方法可能除外),因为 Injector 在运行后才会准备好。@Providesconfigure
2赞 Ferran Maylinch 7/9/2020 #2

您可以在类或提供程序中注入 ,但应很少使用它Injector

我在这里找到了它:https://groups.google.com/d/msg/google-guice/EiMDuDGei1Q/glxFhHKHHjsJ

参见:https://github.com/google/guice/wiki/InjectingTheInjector

public class MyClass
{
    @Inject
    public MyClass(Injector injector) { ... }
}

public class MyModule extends AbstractModule {
    ...

    @Provides
    public Something provideSomething(Injector injector) { ... }

}