[英]Guice: is it possible to inject modules?
我有一個需要一些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<Something>
類。 這顯然是一個簡化的例子; 我正在處理的代碼有許多這樣的@Provides
方法,所以將它們分別切割成單獨的Provider<...>
類並引入一個模塊來配置它們會增加相當多的混亂 - 我認為Guice就是減少樣板雜亂?
也許這反映了我對Guice的相對苛刻,但我遇到了一些我很想做上述事情的案例。 我肯定錯過了什么...
@Provides
方法可以將依賴項作為參數,就像@Inject
注釋的構造函數或方法的參數一樣:
@Provides Something provideSomething(Dependency d) {
return new Something(d); // or whatever
}
這是記錄在這里 ,雖然也許它可以作出更加突出。
如果需要依賴項來手動構造對象,則使用提供程序或@Provides方法非常有用。 但是,如果您需要某些東西來幫助您決定如何配置綁定本身呢? 事實證明,您可以使用Guice來創建(和配置)您的模塊。
這是一個(人為的)例子。 首先,我們要配置的模塊:
/**
* Creates a binding for a Set<String> 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<String> 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<String> pantry = injector.getInstance(new Key<Set<String>>() {});
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<Something>() {
@Inject Dependency d;
Something get() { return d.buildSomething(); }
}
}
}
對於這個簡單的情況,@Provides方法方法比我上面的方法更清晰,但我發現在某些情況下實例化實際的Provider也很有用。 我從郵件列表中偷走了一些東西; 不會發生在我自己身上;)
僅通過調用new MyModule(d)
或通過創建具有注入的Injector
的Provider
來初始化模塊有什么問題? 那些似乎是處理這類問題的標准方法。 如前所述,您還可以將<Something
>@Provides
方法與參數一起使用。
如果依賴項是可選的,則可以創建模塊,然后調用setter以在需要時初始化值(例如, com.google.inject.persist.jpa.JpaPersistModule
使用屬性執行此操作,同時使用new JpaPersistModule(String)
加載正確的配置)。
否則我想可能會這樣做(然后調用createChildInjector(Modules... modules)
),但我幾乎總是喜歡其中一種方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.