Real-Time Bidirectional Config Updates in Spring Boot 3 Without Restart
This tutorial shows how to integrate Apache Commons Configuration2 with Spring Boot 3 to load, refresh, persist, and listen to configuration changes in real time, using periodic reload triggers, auto‑save, and event listeners so updates take effect without restarting the service.
1. Introduction
In modern microservice and distributed systems, static configuration requires a service restart to take effect, which hinders rapid iteration. By combining Spring Boot 3 with Apache Commons Configuration2, we can achieve dynamic loading, real‑time refresh, persistent online modification, and change‑event listening without restarting the application.
2. Environment
Spring Boot version:
3.5.03. Add Dependencies
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-configuration2</artifactId>
<version>2.13.0</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.10.1</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>4. Build Dynamic Configuration
@Configuration
public class ResourceConfig {
@Bean
ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> fileConfiguration(
@Value("${pack.app.path}") String path) {
Parameters parameters = new Parameters();
PropertiesBuilderParameters params = parameters.properties()
.setEncoding("UTF-8")
.setFile(Paths.get(path).toFile())
.setThrowExceptionOnMissing(true);
ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder =
new ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class)
.configure(params);
PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(
builder.getReloadingController(), null, 3, TimeUnit.SECONDS);
trigger.start();
return builder;
}
}The PeriodicReloadingTrigger checks every 3 seconds whether the configuration file has changed and triggers a reload. When a reload occurs, a ReloadingEvent is emitted.
5. Retrieve Configuration at Runtime
@RestController
@RequestMapping("/config")
public class ConfigController {
private final ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder;
public ConfigController(ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> builder) {
this.builder = builder;
}
@GetMapping("/get")
public String getConfig(String key) throws Exception {
FileBasedConfiguration config = this.builder.getConfiguration();
return config.getString(key);
}
}Calling builder.getConfiguration() always returns the latest configuration instance, so the returned value reflects any changes made to the file.
6. Dynamic Modification and Persistence
@Bean
ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> fileConfiguration(
@Value("${pack.app.path}") String path) {
// ... same builder creation as before ...
builder.setAutoSave(true);
return builder;
}
@GetMapping("/set")
public String setConfig(String key, String value) throws Exception {
this.builder.getConfiguration().setProperty(key, value);
return "success";
}Setting builder.setAutoSave(true) automatically writes modified properties back to the file. The /set endpoint updates a property and persists it.
7. Event Listening
@Bean
ReloadingFileBasedConfigurationBuilder<FileBasedConfiguration> fileConfiguration(
@Value("${pack.app.path}") String path) {
// ... builder creation ...
builder.addEventListener(ConfigurationEvent.ANY, event -> {
System.err.println("Property [%s] changed: %s"
.formatted(event.getPropertyName(), event.getPropertyValue()));
});
return builder;
}
// Listening to external file modifications
ReloadingController ctrl = new ReloadingController(
new FileHandlerReloadingDetector(builder.getFileHandler(), 1000));
ctrl.addEventListener(ReloadingEvent.ANY, event -> {
System.err.println("External file modification detected: %s".formatted(event.toString()));
});
PeriodicReloadingTrigger trigger = new PeriodicReloadingTrigger(
ctrl, null, 3, TimeUnit.SECONDS);
trigger.start();When the configuration file is edited with an external tool, the ReloadingEvent listener prints a message, confirming that the change is detected without a restart.
8. Demonstration
Initial configuration file ( config.properties)
pack.app.title=XXXOOO
pack.app.version=1.0.0After calling /set?key=pack.app.title&value=Spring%20Boot3%20Demo, the file is automatically updated to:
pack.app.title=Spring Boot3 实战案例300讲
pack.app.version=1.0.0Images below illustrate the request/response flow and console output of the event listeners.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
