Skip to content

Services

The ServiceRegistry is a lightweight, type-keyed service locator that decouples modules from each other. Instead of passing concrete references between modules directly, each module publishes its services to the registry and other modules resolve them by type.

Any class you want to register must implement Service:

public interface Service {}

This is a marker interface โ€” no methods required. It simply makes the registryโ€™s type parameter explicit.

Services that support hot-reload implement Reloadable:

public interface Reloadable {
void reload() throws Exception;
}

ConfigManager and MessageService implement both Service and Reloadable.

From inside a module that extends AbstractModule:

@Override
public void onEnable() {
MyService service = new MyService(plugin);
provide(MyService.class, service); // registers under MyService.class key
}

Directly via the registry:

plugin.services().register(MyService.class, new MyService(plugin));

Registering the same type twice throws IllegalStateException โ€” one service per type, always.

From inside a module:

MyService service = service(MyService.class); // throws if not registered
Optional<MyService> opt = services().find(MyService.class); // safe

From anywhere with a plugin reference:

MyService service = plugin.services().get(MyService.class);

The registry is cleared (services.clear()) during CorePlugin.onDisable(), after all modules have been disabled. Services should not be resolved after onDisable() is called.

The reference FoundationModule shows how core services are published so all later modules can consume them:

@Override
public void onEnable() {
ConfigManager configs = new ConfigManager(plugin);
provide(ConfigManager.class, configs);
MessageService messages = new MessageService(plugin);
provide(MessageService.class, messages);
SchedulerService scheduler = new SchedulerService(plugin);
provide(SchedulerService.class, scheduler);
ListenerRegistry listeners = new ListenerRegistry(plugin);
provide(ListenerRegistry.class, listeners);
}

A CommandModule that starts after FoundationModule can then do:

MessageService messages = service(MessageService.class);
CommandRegistry commands = new CommandRegistry(plugin, messages);
provide(CommandRegistry.class, commands);