1

我正在使用 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);
    }

}

两个语句都返回 true。但事实并非如此。

我究竟做错了什么?

4

2 回答 2

1

您可能已经检查过这一点——您已经列出了您使用的“那种”绑定——但值得仔细检查一下,在您的未编辑代码中,所涉及的类都没有被谨慎地注释@Singleton或绑定到Singleton.class范围。此外,请确保您的任何绑定都不使用toInstance(),这当然总是在所有情况下都返回该预先构造的实例,并且实际上是单例绑定。

我们有一个案例,我们重构了一个bindView方法,最终忘记了我们将其设置为始终将其参数绑定为单例(这样视图的父容器和视图的控制器可以注入相同的视图)。

除非,正如 Danyel 所暗示的那样, Guice 中编码了循环依赖检测,并且由于您provider.get()@Inject-annotated 方法中调用您的方法,因此您可能正在调用它。

于 2013-02-07T17:04:21.023 回答
0

如果您查看 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]);
    }
}

显然,当您的对象被注入时,Guice 将其存储在该ThreadLocal变量中。现在,根据这个代码片段,它会在注入时立即释放。因此,可能在您的“范围”中,它在其他地方被初始化,可能在注入开始时 - 在注入结束时,它被释放。

于 2013-02-07T17:34:02.040 回答