Java guice-提供程序始终返回相同的实例
我正在使用guice 3和guice servlet 3。在模块中,我定义了此类绑定:Java guice-提供程序始终返回相同的实例,java,dependency-injection,guice,guice-servlet,Java,Dependency Injection,Guice,Guice Servlet,我正在使用guice 3和guice servlet 3。在模块中,我定义了此类绑定: [...] bind(View.class).annotatedWith(Names.named("view1")).to(View1Impl.class); bind(View.class).annotatedWith(Names.named("view2")).to(View2Impl.class); [...] 在注入类View1Impl中,我定义了以下内容: public class View1Im
[...]
bind(View.class).annotatedWith(Names.named("view1")).to(View1Impl.class);
bind(View.class).annotatedWith(Names.named("view2")).to(View2Impl.class);
[...]
在注入类View1Impl中,我定义了以下内容:
public class View1Impl {
@Inject @Named("view1") Provider<View> viewProvider;
@Inject
void init() {
View viewA = viewProvider.get();
View viewB = viewProvider.get();
log.debug(viewA == viewB);
log.debug(viewA == this);
}
}
公共类视图1示例{
@注入@Named(“view1”)提供者viewProvider;
@注入
void init(){
View viewA=viewProvider.get();
View viewB=viewProvider.get();
log.debug(viewA==viewB);
log.debug(viewA==this);
}
}
这两个语句都返回true。但事实并非如此
我做错了什么?您可能已经检查过了——您已经列出了“您使用的那种”绑定——但值得再次检查的是,在未编辑的代码中,没有涉及的类被谨慎地用
@Singleton
注释或绑定到Singleton.class
范围。此外,请确保没有任何绑定使用toInstance()
,这当然会在所有情况下始终返回预构建的实例,并且实际上是一个单例绑定
我们曾经重构过一个bindView
方法,但最终忘记了将其设置为始终将其参数绑定为单例(这样视图的父容器和视图的控制器就可以插入相同的视图)
除此之外,正如Danyel所提到的,还有编码到Guice中的代码,并且由于您在
@Inject
-注释的方法中调用提供者.get()
,您可能正在调用它。您可能已经选中了这一点——您已经列出了“这类”绑定您使用了--但值得仔细检查的是,在未经编辑的代码中,没有涉及的类被谨慎地用@Singleton
注释或绑定到Singleton.class
范围。此外,请确保没有任何绑定使用toInstance()
,这当然会在所有情况下始终返回预构建的实例,并且实际上是一个单例绑定
我们曾经重构过一个bindView
方法,但最终忘记了将其设置为始终将其参数绑定为单例(这样视图的父容器和视图的控制器就可以插入相同的视图)
除此之外,正如Danyel所提到的,Guice中有编码,并且由于您在
@Inject
-注释的方法中调用提供者.get()
,您可能正在调用它。如果您查看Guice的源代码,就会清楚实际执行的操作:
final ThreadLocal<Object[]> localContext;
/** Looks up thread local context. Creates (and removes) a new context if necessary. */
<T> T callInContext(ContextualCallable<T> callable) throws ErrorsException {
Object[] reference = localContext.get();
if (reference[0] == null) {
reference[0] = new InternalContext();
try {
return callable.call((InternalContext)reference[0]);
} finally {
// Only clear the context if this call created it.
reference[0] = null;
}
} else {
// Someone else will clean up this context.
return callable.call((InternalContext)reference[0]);
}
}
final-threadlocalcontext;
/**查找线程本地上下文。如有必要,创建(并删除)新上下文*/
T callInContext(ContextualCallable callable)抛出ErrorsException{
Object[]reference=localContext.get();
if(引用[0]==null){
引用[0]=新的InternalContext();
试一试{
返回callable.call((InternalContext)引用[0]);
}最后{
//仅当此调用创建了上下文时才清除上下文。
引用[0]=null;
}
}否则{
//其他人将清理此上下文。
返回callable.call((InternalContext)引用[0]);
}
}
显然,当注入对象时,Guice将其存储在
ThreadLocal
变量中。现在,根据这个代码片段,它将在被注入时立即被释放。因此,可能在您的“范围”中,它在其他地方被初始化,可能在注入开始时-注入结束时,它被释放。如果您查看Guice的源代码,就会清楚实际执行的操作:
final ThreadLocal<Object[]> localContext;
/** Looks up thread local context. Creates (and removes) a new context if necessary. */
<T> T callInContext(ContextualCallable<T> callable) throws ErrorsException {
Object[] reference = localContext.get();
if (reference[0] == null) {
reference[0] = new InternalContext();
try {
return callable.call((InternalContext)reference[0]);
} finally {
// Only clear the context if this call created it.
reference[0] = null;
}
} else {
// Someone else will clean up this context.
return callable.call((InternalContext)reference[0]);
}
}
final-threadlocalcontext;
/**查找线程本地上下文。如有必要,创建(并删除)新上下文*/
T callInContext(ContextualCallable callable)抛出ErrorsException{
Object[]reference=localContext.get();
if(引用[0]==null){
引用[0]=新的InternalContext();
试一试{
返回callable.call((InternalContext)引用[0]);
}最后{
//仅当此调用创建了上下文时才清除上下文。
引用[0]=null;
}
}否则{
//其他人将清理此上下文。
返回callable.call((InternalContext)引用[0]);
}
}
显然,当注入对象时,Guice将其存储在
ThreadLocal
变量中。现在,根据这个代码片段,它将在被注入时立即被释放。因此,可能在您的“范围”中,它在其他地方初始化,可能在注入开始时-注入结束时,它被释放。您的构造函数在哪里,get
方法具体做什么?@Danyel没有构造函数,因为我不需要构造函数。实例被注入。还有供应商。你真的知道依赖注入是什么吗?你熟悉guice吗?我熟悉,但你的例子真的很奇怪。您正在递归地注入提供程序
。实际上,您很幸运,它返回相同的实例(尽管这也有点奇怪),因为否则您将进入一个无限循环。尝试时:System.out.println(injector.getInstance(View.class)==injector.getInstance(View.class))代码>,返回false
。也许有人可以解释。这是我的问题,因为我认为应该返回false。但我通过进入一个无限循环来理解你的观点。我可能会通过不急于加载视图来解决我的问题。也许guice做循环检测。你的构造函数在哪里,get
方法到底做什么?@Danyel没有构造函数,因为我不需要构造函数。实例被注入。还有供应商。你真的知道依赖注入是什么吗?你熟悉guice吗?我熟悉,但你的例子真的很奇怪。您正在递归地注入提供程序
。你真幸运,它回来了