Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java guice-提供程序始终返回相同的实例_Java_Dependency Injection_Guice_Guice Servlet - Fatal编程技术网

Java guice-提供程序始终返回相同的实例

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

我正在使用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 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吗?我熟悉,但你的例子真的很奇怪。您正在递归地注入
提供程序
。你真幸运,它回来了