Package com.google.inject.internal

Source Code of com.google.inject.internal.SingletonScope

package com.google.inject.internal;

import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.Scope;
import com.google.inject.Scopes;
import com.google.inject.Singleton;

/**
* One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
*/
public class SingletonScope implements Scope {

  /** A sentinel value representing null. */
  private static final Object NULL = new Object();

  /**
   * Lock to use for new instances creation. This allows a per-root-Injector singleton lock,
   * instead of a global lock across the JVM. Is set only during call to {@link #scope}.
   *
   * This is necessary because users have coded to a single {@link Scopes#SINGLETON} instance,
   * and we cannot change that.  Additionally, we can't reference the injector from a Key or
   * Provider (the only variables available to the {@link #scope} method).  Therefore, we rely
   * on the injector implementation to explicitly set/unset the lock surrounding
   * creation of the Provider the scope creates.
   *
   * @see {@link Scoping#scope(Key, InjectorImpl, InternalFactory, Object, Scoping)} for details.
   */
  static final ThreadLocal<Object> singletonCreationPerRootInjectorLock =
      new ThreadLocal<Object>();

  public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
    // lock is referenced from anonymous class instance
    final Object rootInjectorLock = singletonCreationPerRootInjectorLock.get();
    if (rootInjectorLock == null) {
      throw new OutOfScopeException("Singleton scope should only be used from Injector");
    }
    return new Provider<T>() {
      /*
       * The lazily initialized singleton instance. Once set, this will either have type T or will
       * be equal to NULL.
       */
      private volatile Object instance;

      // DCL on a volatile is safe as of Java 5, which we obviously require.
      @SuppressWarnings("DoubleCheckedLocking")
      public T get() {
        if (instance == null) {
          /*
           * Use a pretty coarse lock. We don't want to run into deadlocks
           * when two threads try to load circularly-dependent objects.
           * Maybe one of these days we will identify independent graphs of
           * objects and offer to load them in parallel.
           *
           * This block is re-entrant for circular dependencies.
           */
          synchronized (rootInjectorLock) {
            if (instance == null) {
              T provided = creator.get();

              // don't remember proxies; these exist only to serve circular dependencies
              if (Scopes.isCircularProxy(provided)) {
                return provided;
              }

              Object providedOrSentinel = (provided == null) ? NULL : provided;
              if (instance != null && instance != providedOrSentinel) {
                throw new ProvisionException(
                    "Provider was reentrant while creating a singleton");
              }

              instance = providedOrSentinel;
            }
          }
        }

        Object localInstance = instance;
        // This is safe because instance has type T or is equal to NULL
        @SuppressWarnings("unchecked")
        T returnedInstance = (localInstance != NULL) ? (T) localInstance : null;
        return returnedInstance;
      }

      @Override
      public String toString() {
        return String.format("%s[%s]", creator, Scopes.SINGLETON);
      }
    };
  }

  @Override public String toString() {
    return "Scopes.SINGLETON";
  }
}
TOP

Related Classes of com.google.inject.internal.SingletonScope

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.