Class ServiceRegistry

java.lang.Object
com.zetaplugins.zetacore.di.ServiceRegistry

public class ServiceRegistry extends Object
A registry for managing and injecting service instances.

Besides services and beans, the registry always provides the plugin itself (as JavaPlugin, any supertype or the plugin's own class), the plugin's Logger, the registry itself and its ClassScanner.

The registry is thread-safe. Looking up a singleton that already exists does not lock. Creating, registering and destroying objects happens under a single lock, and an object only becomes visible to other threads once it and every object created along with it are fully injected and initialized. Because constructors, Bean methods and PostConstruct methods run while the lock is held, they must not wait for another thread that itself uses the registry (for example by blocking on a task scheduled on the main thread).

  • Constructor Details

    • ServiceRegistry

      public ServiceRegistry(JavaPlugin plugin)
      Creates a new ServiceRegistry for the given plugin. Doesn't require the Service annotation on managed classes.
      Parameters:
      plugin - The main plugin instance.
    • ServiceRegistry

      public ServiceRegistry(JavaPlugin plugin, boolean requireServiceAnnotation, String packagePrefix)
      Creates a new ServiceRegistry for the given plugin.
      Parameters:
      plugin - The main plugin instance.
      requireServiceAnnotation - Whether to require the Service annotation on managed classes.
      packagePrefix - The package to scan for services.
    • ServiceRegistry

      public ServiceRegistry(JavaPlugin plugin, boolean requireServiceAnnotation, ClassScanner scanner)
      Creates a new ServiceRegistry for the given plugin that uses an existing scanner.
      Parameters:
      plugin - The main plugin instance.
      requireServiceAnnotation - Whether to require the Service annotation on managed classes.
      scanner - The scanner used to discover services.
  • Method Details

    • addResolver

      public void addResolver(InstanceResolver resolver)
      Adds a resolver that supplies instances for types the registry cannot create itself. Resolvers are consulted in the order they were added, before the Service annotation is checked.
      Parameters:
      resolver - The resolver to add.
    • getConditionEvaluator

      public ConditionEvaluator getConditionEvaluator()
      Gets the evaluator for conditions on services, beans, commands and listeners.
      Returns:
      The condition evaluator.
    • getClassScanner

      public ClassScanner getClassScanner()
      Gets the scanner this registry uses to discover services.
      Returns:
      The class scanner.
    • initializeEagerServices

      public void initializeEagerServices()
      Initializes all eagerly loaded singleton services found in the specified package and all registered Beans marked as eagerly loaded.
    • registerConfigurations

      public void registerConfigurations()
      Registers the Bean methods of all Configuration classes found in the scanned package. Beans are created lazily, or by initializeEagerServices() if marked as eagerly loaded.
      Throws:
      ServiceException - If a bean's type is already provided by another bean, a service or a registered instance.
    • registerConfiguration

      public void registerConfiguration(Class<?> configurationClass)
      Registers the Bean methods of a single configuration class. Registering the same class twice has no effect.
      Parameters:
      configurationClass - The class declaring the bean methods.
      Throws:
      ServiceException - If a bean method is invalid or its type is already provided elsewhere.
    • registerInstance

      public void registerInstance(Object instance)
      Registers an existing instance in the registry.
      Parameters:
      instance - The instance to register.
    • registerInstance

      public void registerInstance(Class<?> cls, Object instance)
      Registers an existing instance in the registry under a specific class.
      Parameters:
      cls - The class to register the instance under.
      instance - The instance to register.
    • getOrCreate

      public <T> T getOrCreate(Class<T> cls)
      Gets an existing instance of the specified class, or creates one if it doesn't exist.
      Type Parameters:
      T - The type of the instance.
      Parameters:
      cls - The class of the instance to get or create.
      Returns:
      The existing or newly created instance.
    • getAll

      public <T> List<T> getAll(Class<T> type)
      Gets all active providers of the given type: registered instances, Beans whose declared type is assignable to it and active singleton Service classes that implement it. Each provider is created if needed.

      Useful for optional extension points such as customizers, where any number of implementations may exist.

      Type Parameters:
      T - The type.
      Parameters:
      type - The type to look up.
      Returns:
      The instances, without duplicates. Empty if there are none.
    • getSingletonCount

      public int getSingletonCount()
      Gets the number of singleton services, beans and registered instances created so far.
      Returns:
      The number of distinct singletons.
    • create

      public <T> T create(Class<T> cls)
      Creates a new, unregistered instance of the specified class with full dependency injection.

      The instance is constructed via constructor injection (see createInstance(Class)), then its Inject-annotated fields are injected and its PostConstruct methods are called. The created object itself is not stored in the registry, which makes this suitable for objects like commands or listeners that depend on services but aren't services themselves.

      Type Parameters:
      T - The type of the instance.
      Parameters:
      cls - The class to instantiate.
      Returns:
      The newly created and injected instance.
    • shutdown

      public void shutdown()
      Destroys all managed objects in reverse creation order.

      For each object, its PreDestroy methods are called, then AutoCloseable.close() if the object implements it and close() is not itself annotated with PreDestroy. Prototype services are not managed. Errors are logged and do not stop the remaining objects from being destroyed. Calling this again has no effect unless new objects were created in the meantime.

    • injectServices

      public void injectServices(Object target)
      Injects service instances into the fields of the target object.
      Parameters:
      target - The target object to inject services into.