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

Java 如何使用Guice注射器创建对象?,java,constructor,guice,Java,Constructor,Guice,我的代码中有: private static class BaseScriptInfoParser extends NodeParser<Asset.ScriptInfo> { private Asset.ScriptKindEnum scriptKind; private final NodeParser<Asset.TransformerKindEnum> transformerKindNodeParser; private final N

我的代码中有:

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
类的对象,该对象有一个参数(属于
Asset.ScriptKindEnum
type),并自动注入前两个参数

或者,使用注入器创建对象是如何工作的


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

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

通常,您应该从图形中注入所需的对象。如果您认为您以后可能只需要一个对象,或者您可能需要一个对象的多个实例,那么您可以插入一个
提供者
(T是图中可用的任何对象),然后您可以稍后请求该实例,就像调用
getInstance
(但无需创建新对象或提供其余图形)。这也会使测试更容易,因为模拟喷油器很困难,而且使用真实喷油器既昂贵又复杂

如果BaseScriptInfoParser没有此手动第三个参数,您可以只插入
提供程序
:只要
BaseScriptInfoParser
具有公共无参数构造函数、
@inject
注释构造函数或
绑定(BaseScriptInfoParser.class),Guice就会自动处理此问题
绑定或
@在模块中提供BaseScriptInfoParser
方法


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

并非图形中的每个对象都需要是可注入的:要使用Miško Hevery的术语,您的应用程序很可能由来自图形的可注入内容组成,其中包含一些新的内容,如“值对象”和“数据对象”,它们具有大量状态且没有依赖性

但是,对于某些对象,让构造函数提供不可变状态是有意义的,同时也可以从图中访问可注入项,而不必将两者分离为单独的对象(这也是一个选项)。实际上,您想要的是DI框架可以提供的一个对象,它满足此接口:

interface BaseScriptInfoParserFactory {
  /**
   * Calls the BaseScriptInfoParser constructor, with other constructor params
   * injected from the graph.
   */
  BaseScriptInfoParser create(Asset.ScriptKindEnum scriptKind);
}
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
}
因为这是一个定义非常好的类,所以Google为如何自动生成一个类提供了两种不同的选项:您可以使用Guice的反射类,也可以使用代码生成包。后者要快一点,因为它生成的是普通代码而不是运行时反射代码,但前者稍微集成了带Guice的etter:

  • 确保Guice辅助注入JAR位于类路径上。它是独立的

  • 标记构造函数以说明哪些参数应来自Guice:

    @Inject BaseScriptInfoParser(
          @Named("transformerKind") NodeParser<...> transformerKindNodeParser,
          @Named("validatorKind") NodeParser<...> validatorKindNodeParser,
          @Assisted Asset.ScriptKindEnum scriptKind)
    
  • 告诉Guice编写一个实现并绑定到它:

    public class YourModule extends AbstractModule {
      @Override public void configure() {
        install(new FactoryModuleBuilder()
            .build(BaseScriptInfoParser.Factory.class));
      }
    }
    
  • 插入
    BaseScriptInfoParser.Factory
    并在需要新对象时调用
    create(someScriptKind)


  • 如何执行项目“5”(inject
    BaseScriptInfoParser.Factory
    )?在主类中使用您的注入器注入该类型的字段,或者在那里调用getInstance,或者一路上注入每个依赖项,直到您可以在需要它的类中简单地
    @injectBaseScriptInfoParser.Factory
    。您没有向我们展示谁使用BaseScriptInfoParser.Factory,只是您试图不创建第二个Inj埃克托,所以我只能同意你的策略。
    public class YourModule extends AbstractModule {
      @Override public void configure() {
        install(new FactoryModuleBuilder()
            .build(BaseScriptInfoParser.Factory.class));
      }
    }