如何使用Guice注入器创建对象?



我的代码中有:

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实例(因为据我所知,它应该只在 Main 函数中)

Injector injector = Guice.createInjector(new BoilerModule());
// ...

我可以只调用构造函数来创建具有一个参数(Asset.ScriptKindEnum类型)的类BaseScriptInfoParser对象并自动注入前两个参数吗?

或者如何使用注入器创建对象?

如果构造函数BaseScriptInfoParser没有第三个参数,它将如何工作?

您避免对createInjector进行额外调用是正确的,并避免传递您创建的注入器。对于最佳Guice实践,您应该准确指定任何给定组件创建或依赖的对象,而Injector与此相反:它可以创建任何东西。

相反,通常,您应该从图形中注入所需的对象。如果您认为以后可能只需要一个对象,或者可能需要对象的多个实例,则可以改为注入Provider<T>(其中 T 是图形中可用的任何对象),然后您可以稍后请求该实例,就像调用getInstance一样(但不创建新对象或使图形的其余部分可用)。这也应该使测试变得更加容易,因为在测试中模拟提供程序非常容易,但模拟注入器很困难,并且使用真正的注入器既昂贵又复杂。

如果 BaseScriptInfoParser 没有这个手动的第三个参数,你可以注入Provider<BaseScriptInfoParser>:只要模块中有一个公共无参数构造函数、一个@Inject注释构造函数或bind(BaseScriptInfoParser.class)绑定或@Provides BaseScriptInfoParser方法,Guice 就会自动处理BaseScriptInfoParser


现在,关于混合注入的构造函数参数和非注入的参数:

并非图形中的每个对象都需要是可注入的:使用Miško Hevery在他的"new或不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 辅助注入 JAR 位于类路径上。它是分开的。

  2. 标记你的构造函数,说明哪些参数应该来自Guice:

    @Inject BaseScriptInfoParser(
    @Named("transformerKind") NodeParser<...> transformerKindNodeParser,
    @Named("validatorKind") NodeParser<...> validatorKindNodeParser,
    @Assisted Asset.ScriptKindEnum scriptKind)
    
  3. 编写一个可以注入的工厂接口,我喜欢将其作为嵌套接口:

    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)

最新更新