Pregunta

I am working with guice 3 and guice-servlet 3. In the module I defined bindings of this sort:

[...]
bind(View.class).annotatedWith(Names.named("view1")).to(View1Impl.class);
bind(View.class).annotatedWith(Names.named("view2")).to(View2Impl.class);
[...]

In the injected class View1Impl I defined following:

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);
    }

}

Both statements return true. But that should not be the case.

What am I doing wrong?

¿Fue útil?

Solución 2

If you look inside Guice's source code, it will be clear what is actually done:

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]);
    }
}

Apparently, when your object is injected, Guice stores it in that ThreadLocal variable. Now, this according to this code snippet, it will instantly be released as it is injected. So, probably in your "scope" it is initialized somewhere else, probably at the beginning of the injection - and at the end of the injection, it is released.

Otros consejos

You might have already checked this--you've listed bindings "of the sort" you use--but it's worth double-checking that in your non-redacted code none of the classes involved are discreetly annotated with @Singleton or bound to the Singleton.class scope. Furthermore, ensure that none of your bindings use toInstance(), which will of course always return that pre-constructed instance in all cases and is effectively a singleton binding.

We had a case where we'd refactored out a bindView method and eventually forgot that we'd set it up to always bind its argument as a singleton (such that the view's parent container and view's controller could inject the same view).

Barring that, as Danyel alluded to, there is circular dependency detection coded into Guice, and since you are calling your provider.get() within a @Inject-annotated method, you may be invoking it.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top