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.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Real-Time Bidirectional Config Updates in Spring Boot 3 Without Restart

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.0

3. 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.0

After 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.0

Images below illustrate the request/response flow and console output of the event listeners.

Initial request result
Initial request result
After modification result
After modification result
Console output of property change
Console output of property change
External file edit detection
External file edit detection
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaDynamic ConfigurationSpring Bootevent-listenerApache Commons Configuration2Auto Save
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.