[英]How to create objects with Guice injectors?
我的代碼中有:
private static class BaseScriptInfoParser extends NodeParser<Asset.ScriptInfo> {
private Asset.ScriptKindEnum scriptKind;
private final NodeParser<Asset.TransformerKindEnum> transformerKindNodeParser;
private final NodeParser<Asset.ValidatorKindEnum> validatorKindNodeParser;
@Inject
BaseScriptInfoParser(
// First two arguments are injectors
@Named("transformerKind") NodeParser<Asset.TransformerKindEnum> transformerKindNodeParser,
@Named("validatorKind") NodeParser<Asset.ValidatorKindEnum> validatorKindNodeParser,
Asset.ScriptKindEnum scriptKind)
{
this.scriptKind = scriptKind;
this.transformerKindNodeParser = transformerKindNodeParser;
this.validatorKindNodeParser = validatorKindNodeParser;
}
// ...
}
現在我想創建一個沒有代碼的BaseScriptInfoParser
實例(因為據我BaseScriptInfoParser
它應該只在Main函數中)
Injector injector = Guice.createInjector(new BoilerModule());
// ...
我可以只調用一個構造函數來創建一個BaseScriptInfoParser
類的對象,該對象具有一個參數( Asset.ScriptKindEnum
類型),並且前兩個參數是自動注入的嗎?
或者如何使用注射器創建物體?
如果構造函數BaseScriptInfoParser
沒有第三個參數,它將如何工作?
您是正確的,以避免額外調用createInjector
,並避免傳遞您創建的Injector。 為了獲得最佳Guice實踐,您應該准確指定任何給定組件創建或依賴的對象,而Injector則與之相反:它可以創建任何內容。
相反,通常,您應該從圖中注入所需的對象。 如果您認為以后可能只需要一個對象,或者您可能需要多個對象實例,則可以注入Provider<T>
(其中T是圖中可用的任何對象),然后您可以稍后請求該實例好像你調用了getInstance
(但沒有創建新對象或者使圖表的其余部分可用)。 這應該使測試更容易,因為在測試中模擬提供者非常容易 ,但是模擬注入器很困難,並且使用真正的注入器是昂貴且復雜的。
如果BaseScriptInfoParser沒有這個手動的第三個參數,你可以只注入Provider<BaseScriptInfoParser>
:只要BaseScriptInfoParser
有一個公共無參數構造函數,一個@Inject
注釋的構造函數或一個bind(BaseScriptInfoParser.class)
綁定,Guice就會自動處理它或@Provides BaseScriptInfoParser
模塊中的@Provides BaseScriptInfoParser
方法。
現在,關於混合注入的構造函數參數和非注入參數:
並非圖中的每個對象都需要注入:要使用MiškoHevery的術語,從他的“To new
or not to new
”文章中 ,您的應用程序很可能由來自圖表的注射劑組成,並帶有一些新的東西,如“值對象”和“數據對象”具有大量的狀態和沒有依賴關系。
但是,對於某些對象,有了構造函數提供的不可變狀態,同時還從圖中訪問注入 ,而不將兩者分成單獨的對象(這也是一個選項)是有意義的。 實際上,您所希望的是DI框架可以提供的對象,它實現了以下接口:
interface BaseScriptInfoParserFactory {
/**
* Calls the BaseScriptInfoParser constructor, with other constructor params
* injected from the graph.
*/
BaseScriptInfoParser create(Asset.ScriptKindEnum scriptKind);
}
因為這是一個非常明確的類,所以Google提供了幾種不同的選項來自動生成一個:您可以使用Guice的反射輔助注入或來自代碼生成Google Auto軟件包的AutoFactory 。 后者有點快,因為它生成普通代碼而不是運行時反射代碼,但前者與Guice集成得更好:
確保Guice Assisted Injection JAR在類路徑上。 它是分開的。
標記你的構造函數,說出哪些參數應該來自Guice:
@Inject BaseScriptInfoParser( @Named("transformerKind") NodeParser<...> transformerKindNodeParser, @Named("validatorKind") NodeParser<...> validatorKindNodeParser, @Assisted Asset.ScriptKindEnum scriptKind)
編寫一個可以注入的Factory接口,我喜歡將其作為嵌套接口:
public class BaseScriptInfoParser { public interface Factory { // Any interface and method name works. These are the most common. BaseScriptInfoParser create(Asset.ScriptKindEnum scriptKind); } // ... rest of the class, including the above constructor }
告訴Guice寫一個實現並綁定到它:
public class YourModule extends AbstractModule { @Override public void configure() { install(new FactoryModuleBuilder() .build(BaseScriptInfoParser.Factory.class)); } }
注入BaseScriptInfoParser.Factory
並在需要新對象時調用create(someScriptKind)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.