How to Listen to Reload Events Using the ReloadListener Interface in Owner
Implement the org.aeonbits.owner.event.ReloadListener interface and register it via addReloadListener() on your configuration instance to receive callbacks after each successful reload.
The Owner configuration library (matteobaccan/owner) provides a robust event system that notifies your application when configuration properties change. By leveraging the ReloadListener interface, you can execute custom logic—such as refreshing caches, logging changes, or triggering notifications—immediately after a reload completes.
Understanding the ReloadListener Interface
The ReloadListener interface, defined in owner/src/main/java/org/aeonbits/owner/event/ReloadListener.java, declares a single callback method:
void reloadPerformed(ReloadEvent event);
Owner invokes this method after the properties have been successfully reloaded, ensuring that any logic inside reloadPerformed can safely read updated values from the configuration object. The ReloadEvent parameter, implemented in owner/src/main/java/org/aeonbits/owner/event/ReloadEvent.java, provides metadata about the reload operation, including the source configuration instance and the timestamp of the event.
Registering a ReloadListener
To begin listening for reload events, create an instance of ReloadListener and register it using the addReloadListener() method available on any configuration object that extends Reloadable.
import org.aeonbits.owner.ConfigFactory;
import org.aeonbits.owner.Config;
import org.aeonbits.owner.Reloadable;
import org.aeonbits.owner.event.ReloadListener;
import org.aeonbits.owner.event.ReloadEvent;
@Sources("file:app.properties")
public interface AppConfig extends Config, Reloadable {
@DefaultValue("localhost")
String databaseHost();
@DefaultValue("5432")
Integer databasePort();
}
public class ConfigMonitor {
public static void main(String[] args) {
AppConfig config = ConfigFactory.create(AppConfig.class);
// Register anonymous listener
config.addReloadListener(new ReloadListener() {
@Override
public void reloadPerformed(ReloadEvent event) {
System.out.println("Configuration reloaded at " + event.getTimestamp());
System.out.println("New database host: " + config.databaseHost());
}
});
// Keep application running to receive reload events
}
}
Internally, ConfigFactory.create() builds a proxy that maintains a thread-safe list of listeners (see PropertiesManager.addReloadListener in the source). When Config.reload() or a hot-reload detection triggers a reload, Owner iterates over that list and invokes listener.reloadPerformed(event).
Accessing ReloadEvent Details
The ReloadEvent object passed to your listener contains two critical pieces of information:
event.getConfig(): Returns the configuration instance that was reloaded, allowing you to access updated properties.event.getTimestamp(): Returns the Unix timestamp (milliseconds) when the reload occurred.
config.addReloadListener(event -> {
Reloadable sourceConfig = event.getConfig();
long reloadTime = event.getTimestamp();
// Log the change for audit purposes
logger.info("Config {} reloaded at {}", sourceConfig, new Date(reloadTime));
});
Removing a ReloadListener
When a listener is no longer needed—such as during application shutdown or when a component is destroyed—you should unregister it to prevent memory leaks. Use the removeReloadListener() method:
ReloadListener myListener = event -> { /* ... */ };
config.addReloadListener(myListener);
// Later, when cleaning up:
config.removeReloadListener(myListener);
Practical Example: Hot-Reload with Listener
For file-based configurations using @Config.HotReload, combining automatic reloading with a listener creates a powerful dynamic configuration system. The following example, adapted from owner-examples/owner-examples-hotreload/src/main/java/org/aeonbits/owner/examples/AutoReloadExample.java, demonstrates this pattern:
import org.aeonbits.owner.Config;
import org.aeonbits.owner.ConfigFactory;
import org.aeonbits.owner.Reloadable;
import org.aeonbits.owner.event.ReloadListener;
import org.aeonbits.owner.event.ReloadEvent;
@Config.HotReload(5) // Check for changes every 5 seconds
@Config.Sources("file:/etc/myapp/config.properties")
public interface DynamicConfig extends Config, Reloadable {
@DefaultValue("INFO")
String logLevel();
@DefaultValue("300")
Integer connectionTimeout();
}
public class HotReloadMonitor {
public static void main(String[] args) throws InterruptedException {
DynamicConfig config = ConfigFactory.create(DynamicConfig.class);
// Register listener to react to file changes
config.addReloadListener(new ReloadListener() {
@Override
public void reloadPerformed(ReloadEvent event) {
System.out.printf("[%d] Config reloaded! New log level: %s, Timeout: %d%n",
event.getTimestamp(),
config.logLevel(),
config.connectionTimeout());
// Trigger cache invalidation or service reconfiguration here
}
});
System.out.println("Monitoring config changes. Edit the file to trigger reload...");
while (true) {
Thread.sleep(1000);
}
}
}
In this implementation, Owner monitors the specified file every 5 seconds. When a modification is detected, it reloads the properties and immediately notifies all registered ReloadListener instances, allowing the application to adapt to new settings without restart.
Summary
- Implement
org.aeonbits.owner.event.ReloadListenerto receive callbacks when configuration reloads complete. - Register listeners using
addReloadListener()on any configuration instance that implementsReloadable. - Access reload metadata through
ReloadEvent, includinggetConfig()andgetTimestamp(). - Remove listeners with
removeReloadListener()to prevent memory leaks when components shut down. - Listeners work with both programmatic reloads (
Config.reload()) and automatic hot-reloads (@Config.HotReload).
Frequently Asked Questions
How do I register multiple ReloadListeners on the same configuration instance?
You can call addReloadListener() multiple times on the same configuration object. Owner maintains a thread-safe list of listeners and invokes each one sequentially after a reload completes. There is no limit to the number of listeners you can register.
Can I remove a ReloadListener after registering it?
Yes. Store a reference to your ReloadListener implementation and pass it to removeReloadListener() when you no longer need notifications. This is important for preventing memory leaks in long-running applications where configuration objects outlive the components that registered the listeners.
What information does the ReloadEvent object contain?
The ReloadEvent object provides two key pieces of metadata: getConfig(), which returns the configuration instance that was reloaded, and getTimestamp(), which returns the Unix timestamp (in milliseconds) when the reload occurred. You can use these to log changes or trigger conditional logic based on when the reload happened.
Does the ReloadListener work with both manual and automatic reloads?
Yes. The ReloadListener interface is invoked whenever a reload completes, regardless of whether it was triggered manually via Config.reload() or automatically through the @Config.HotReload annotation. This ensures consistent behavior across programmatic and file-based configuration updates.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →