繁体   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