Guice:可以注入模块吗?

我有一个需要一些Depedency的模块。 有没有办法可以注入模块本身? 我意识到这有点鸡蛋和鸡蛋的情况……

例:

 public class MyModule implements Module { private final Dependency d_; @Inject public MyModule(Dependency d) { d_ = d; } public void configure(Binder b) { } @Provides Something provideSomething() { // this requires d_ } } 

我想在这种情况下,解决方案是将@Provides方法转换为完整的Provider类。 这显然是一个简化的例子; 我正在处理的代码有很多这样的@Provides方法,所以将它们分别切割成单独的Provider类并引入一个模块来配置它们会增加相当多的混乱 – 我认为Guice就是减少样板杂乱?

也许这反映了我对Guice的相对苛刻,但我遇到了一些我很想做上述事情的案例。 我肯定错过了什么…

@Provides方法可以将依赖项作为参数,就像@Inject注释的构造函数或方法的参数一样:

 @Provides Something provideSomething(Dependency d) { return new Something(d); // or whatever } 

这里记录了这一点,但也许它可以更突出。

如果需要依赖项来手动构造对象,则使用提供程序或@Provides方法非常有用。 但是,如果您需要某些东西来帮助您决定如何配置绑定本身呢? 事实certificate,您可以使用Guice来创建(和配置)您的模块。

这是一个(人为的)例子。 首先,我们要配置的模块:

 /** * Creates a binding for a Set which represents the food in a pantry. */ public class PantryModule extends AbstractModule { private final boolean addCheese; @Inject public ConditionalModule(@Named("addCheese") boolean addCheese) { this.addCheese = addCheese; } @Override protected void configure() { Multibinder pantryBinder = Multibinder .newSetBinder(binder(), String.class); pantryBinder.addBinding().toInstance("milk"); if (addCheese) { pantryBinder.addBinding().toInstance("cheese"); } pantryBinder.addBinding().toInstance("bread"); } } 

PantryModule需要注入一个布尔值来决定它是否应该在食品室中包含奶酪。

接下来,我们将使用Guice配置模块:

 // Here we use an anonymous class as the "configuring" module. In real life, you would // probably use a standalone module. Injector injector = Guice.createInjector(new AbstractModule() { @Override protected void configure() { // No cheese please! bindConstant().annotatedWith(Names.named("addCheese")).to(false); bind(PantryModule.class); } }); Module configuredConditionalModule = injector.getInstance(PantryModule.class); 

现在我们已经配置了模块,我们将更新我们的注入器以使用它…

 //...continued from last snippet... injector = injector.createChildInjector(configuredConditionalModule); 

最后我们将获得代表我们食品室的字符串集:

 //...continued from last snippet... Set pantry = injector.getInstance(new Key>() {}); for (String food : pantry) { System.out.println(food); } 

如果您将所有部分放在一个main方法中并运行它,您将获得以下输出:

 milk bread 

如果将绑定更改为“addCheese”布尔值为true,您将获得:

 milk cheese bread 

这种技术很酷,但可能仅在您控制Injector实例并且仅在模块需要复杂依赖项时才有用。 毫无道理,我发现在一个真正的工作项目中真正需要这个。 如果我这样做,那么其他人也可能。

这个问题已经得到了很好的回答,但我只想为Colin的例子添加一个变体:

 class MyModule extends AbstractModule { public void configure() { bind(Something.class).toProvider(new Provider() { @Inject Dependency d; Something get() { return d.buildSomething(); } } } } 

对于这个简单的情况,@Provides方法方法比我上面的方法更清晰,但我发现在某些情况下实例化实际的Provider也很有用。 我从邮件列表中偷走了一些东西; 不会发生在我自己身上;)

仅通过调用new MyModule(d)或通过创建具有注入的InjectorProvider >来初始化模块有什么问题? 这些似乎是处理这类问题的标准方法。 如前所述,您还可以将@Provides方法与参数一起使用。

如果依赖项是可选的,则可以创建模块,然后调用setter以在需要时初始化值(例如, com.google.inject.persist.jpa.JpaPersistModule使用属性执行此操作,同时使用new JpaPersistModule(String)加载正确的配置)。

否则我想可能会这样做(然后调用createChildInjector(Modules... modules) ),但我几乎总是喜欢其中一种方法。