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