doGetSingleton method

  1. @protected
Future<TypedInstance?> doGetSingleton(
  1. String name, {
  2. bool allowEarlyReference = true,
  3. ObjectFactory<Object>? factory,
})
inherited

Get the singleton instance for the given name.

This method is used to retrieve the singleton instance for the given name.

name: The name of the singleton to retrieve allowEarlyReference: Whether to allow early references to the singleton factory: The factory to use to create the singleton if necessary

Example:

final userService = registry.doGetSingleton('userService');

Implementation

@protected
Future<TypedInstance?> doGetSingleton(String name, {bool allowEarlyReference = true, ObjectFactory<Object>? factory}) async {
  if(factory != null) {
    return synchronized(_singletons, () async {
      // 1️⃣ Check if already created
      ObjectHolder<Object>? singleton = _singletons[name];

      Object? result = singleton?.getValue();
      Class? resultType = singleton?.getType();

      if (result == null) {
        // 2️⃣ Prevent creation during destruction phase
        if (_singletonsCurrentlyInDestruction) {
          throw PodCreationNotAllowedException(
            name: name,
            'Singleton pod creation not allowed while singletons of this factory are in destruction (Do not request a pod from a PodFactory in a destroy method implementation!)'
          );
        }

        if (_logger.getIsTraceEnabled()) {
          _logger.trace("Creating shared instance of pod $name");
        }

        // 3️⃣ Mark as in creation
        try {
          beforeSingletonCreation(name);
        } on PodCurrentlyInCreationException catch (_) {
          _singletonFactories[name] = factory;
          final cached = await getSingletonCache(name, allowEarlyReference);

          if (cached != null) {
            final resultType = cached.getType();

            if (resultType != null) {
              _singletonTypes[name] = resultType;
            }

            return TypedInstance(cached.getValue(), resultType);
          }

          beforeSingletonCreation(name);
        }

        bool newSingleton = false;
        bool recordSuppressedExceptions = (_suppressedExceptions.get()?.isEmpty ?? true);
        if (recordSuppressedExceptions) {
          _suppressedExceptions.get()?.clear();
        }

        try {
          singleton = await factory.get();
          result = singleton.getValue();
          resultType = singleton.getType();

          newSingleton = true;
        } on IllegalStateException catch (_) {
          // If factory indicates the state changed and the singleton implicitly appeared,
          // prefer the cache instance if present; otherwise rethrow.
          singleton = _singletons[name];
          if (singleton == null) {
            rethrow;
          }

          result = singleton.getValue();
          resultType = singleton.getType();
        } catch (e) {
          if (recordSuppressedExceptions) {
            for (final ex in _suppressedExceptions.get()!) {
              onSuppressedException(ex);
            }
          }
          rethrow;
        } finally {
          if (recordSuppressedExceptions) {
            _suppressedExceptions.get()?.clear();
          }
          afterSingletonCreation(name);
        }

        // If we created the singleton, register it (tolerate implicit duplicate)
        if (newSingleton) {
          try {
            addSingleton(name, object: singleton);
          } on IllegalStateException catch (_) {
            // Another concurrent path may have registered the same pod.
            // Accept the existing instance if it's identical; otherwise rethrow.
            final existing = _singletons[name];
            if (result != existing?.getValue()) {
              rethrow;
            }
          }
        }
      }

      if (resultType != null) {
        _singletonTypes[name] = resultType;
      }

      return TypedInstance(result, resultType);
    });
  } else {
    final singleton = await getSingletonCache(name, allowEarlyReference);

    if (singleton != null) {
      return TypedInstance(singleton.getValue(), singleton.getType());
    } else {
      return null;
    }
  }
}