Search code examples
javadependency-injectionguiceguice-servlet

guice - Provider returns always same instance


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?


Solution

  • 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.