aboutsummaryrefslogtreecommitdiff
path: root/core/src/com/google/inject/internal/InjectorImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/com/google/inject/internal/InjectorImpl.java')
-rw-r--r--core/src/com/google/inject/internal/InjectorImpl.java51
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);
+ }
+ }
}
}