Reputation: 4104
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?
Upvotes: 1
Views: 2712
Reputation: 2250
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.
Upvotes: 0
Reputation: 95764
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.
Upvotes: 1