diff options
Diffstat (limited to 'core/src/com/google/inject/internal/InjectorImpl.java')
-rw-r--r-- | core/src/com/google/inject/internal/InjectorImpl.java | 51 |
1 files changed, 44 insertions, 7 deletions
diff --git a/core/src/com/google/inject/internal/InjectorImpl.java b/core/src/com/google/inject/internal/InjectorImpl.java index 3d868eba..54ce8a3c 100644 --- a/core/src/com/google/inject/internal/InjectorImpl.java +++ b/core/src/com/google/inject/internal/InjectorImpl.java @@ -57,6 +57,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentMap; /** * Default {@link Injector} implementation. @@ -709,8 +710,7 @@ final class InjectorImpl implements Injector, Lookups { @SuppressWarnings("unchecked") Key<? extends Provider<T>> providerKey = (Key<? extends Provider<T>>) Key.get(providerType); ProvidedByInternalFactory<T> internalFactory = - new ProvidedByInternalFactory<T>(rawType, providerType, - providerKey, !options.disableCircularProxies); + new ProvidedByInternalFactory<T>(rawType, providerType, providerKey); Object source = rawType; BindingImpl<T> binding = LinkedProviderBindingImpl.createWithInitializer( this, @@ -1051,7 +1051,31 @@ final class InjectorImpl implements Injector, Lookups { return getProvider(type).get(); } + /** @see #getGlobalInternalContext */ private final ThreadLocal<Object[]> localContext; + /** + * Synchronization: map value is modified only for the current thread, + * it's ok to read map values of other threads. It can change between your + * calls. + * + * @see #getGlobalInternalContext + */ + private static final ConcurrentMap<Thread, InternalContext> globalInternalContext = + Maps.newConcurrentMap(); + + /** + * Provides access to the internal context for the current injector of all threads. + * One does not need to use this from Guice source code as context could be passed on the stack. + * It is required for custom scopes which are called from Guice and sometimes do require + * access to current internal context, but it is not passed in. Contrary to {@link #localContext} + * it is not used to store injector-specific state, but to provide easy access to the current + * state. + * + * @return unmodifiable map + */ + static Map<Thread, InternalContext> getGlobalInternalContext() { + return Collections.unmodifiableMap(globalInternalContext); + } /** Looks up thread local context. Creates (and removes) a new context if necessary. */ <T> T callInContext(ContextualCallable<T> callable) throws ErrorsException { @@ -1060,17 +1084,30 @@ final class InjectorImpl implements Injector, Lookups { reference = new Object[1]; localContext.set(reference); } + Thread currentThread = Thread.currentThread(); if (reference[0] == null) { - reference[0] = new InternalContext(); + reference[0] = new InternalContext(options); + globalInternalContext.put(currentThread, (InternalContext) reference[0]); try { - return callable.call((InternalContext)reference[0]); + return callable.call((InternalContext) reference[0]); } finally { - // Only clear the context if this call created it. + // Only clear contexts if this call created them. reference[0] = null; + globalInternalContext.remove(currentThread); } } else { - // Someone else will clean up this context. - return callable.call((InternalContext)reference[0]); + Object previousGlobalInternalContext = globalInternalContext.get(currentThread); + globalInternalContext.put(currentThread, (InternalContext) reference[0]); + try { + // Someone else will clean up this local context. + return callable.call((InternalContext) reference[0]); + } finally { + if (previousGlobalInternalContext != null) { + globalInternalContext.put(currentThread, (InternalContext) previousGlobalInternalContext); + } else { + globalInternalContext.remove(currentThread); + } + } } } |