簡體   English   中英

如何使用Guice注射器創建對象?

[英]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集成得更好:

  1. 確保Guice Assisted Injection JAR在類路徑上。 它是分開的。

  2. 標記你的構造函數,說出哪些參數應該來自Guice:

     @Inject BaseScriptInfoParser( @Named("transformerKind") NodeParser<...> transformerKindNodeParser, @Named("validatorKind") NodeParser<...> validatorKindNodeParser, @Assisted Asset.ScriptKindEnum scriptKind) 
  3. 編寫一個可以注入的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 } 
  4. 告訴Guice寫一個實現並綁定到它:

     public class YourModule extends AbstractModule { @Override public void configure() { install(new FactoryModuleBuilder() .build(BaseScriptInfoParser.Factory.class)); } } 
  5. 注入BaseScriptInfoParser.Factory並在需要新對象時調用create(someScriptKind)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM