Java Scenario Based Interview Question 5: How to Dynamically Reload Configuration Files in…
Introduction: Why This Matters
Java Scenario Based Interview Question 5: How to Dynamically Reload Configuration Files in Non-Spring Java Applications
Introduction: Why This Matters
Imagine you’re building a Java application that connects to a database. You’ve wisely put the database connection details in a configuration file rather than hardcoding them. But what happens when the database password changes? Or when you need to adjust some settings while your application is running?
In the old days, you’d have to:
- Stop your application
- Edit the config file
- Restart your application
- Cross your fingers hoping nothing breaks during the restart
That’s like having to turn off your car’s engine just to adjust the radio volume! There must be a better way.
In this guide, I’ll show you how to build a Java solution that automatically detects changes in your configuration file and reloads the new values — without restarting your application. This is a superpower that professional Java developers use every day!

What We’re Building: A Real-World Example
Let’s say we’re building a weather service application with these requirements:
- Runs 24/7 to provide weather updates
- Connects to multiple data sources
- Has adjustable settings like update frequency and data thresholds
- Needs to adapt to changes without downtime
Our solution will:
- Watch a configuration file for changes
- Automatically reload new values when detected
- Keep working with old values if the new config has errors
- Be efficient (no constant file reading)
Understanding the Problem Deeply
Why Simple Solutions Don’t Work
Naive Approach #1: Read the file every time you need a setting
String getDatabaseUrl() {
// This is BAD - file I/O on every call is slow!
Properties props = new Properties();
props.load(new FileInputStream("config.properties"));
return props.getProperty("db.url");
}
Naive Approach #2: Read once at startup and never update
// This is better but doesn't handle runtime changes
class Config {
static final String DB_URL = // read from file at startup
}
The Goldilocks Solution
We need something that:
- Reads the file once at startup
- Watches for changes in the background
- Only reloads when needed
- Handles errors gracefully
Get the Full Code Implementation
Want to dive right into the code? The complete implementation of this dynamic configuration reloader — including error handling, thread safety, and file watcher logic — is available on GitHub:
🔗 **GitHub Repository: Dynamic Config Reloader**
Step-by-Step Implementation
Step 1: Setting Up Your Project
First, let’s add the necessary libraries to your pom.xml:
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
<version>1.4.2</version>
</dependency>
Step 2: Creating a Sample Config File
Create a file named test.conf in your project directory with this content:
app {
name = "TestApp123"
version = "1.0.0"
enabled = true
maxConnections = 10
}
This uses the HOCON format (Human-Optimized Config Object Notation), which is like JSON but more readable and flexible.
Step 3: Building the DynamicConfig Class
package com.raju.codekatas.configsync.config;
import com.raju.codekatas.configsync.watcher.ConfigFileWatcher;
import com.raju.codekatas.configsync.watcher.NioConfigFileWatcher;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
public class DynamicConfig implements Closeable {
private static final Logger logger = LoggerFactory.getLogger(DynamicConfig.class);
private final File configFile;
private final ConfigFileWatcher fileWatcher;
private final AtomicReference<Config> cachedConfig = new AtomicReference<>();
private volatile long lastModified;
public DynamicConfig(File configFile, ConfigFileWatcher fileWatcher) {
this.configFile = Objects.requireNonNull(configFile, "Config file must not be null");
this.fileWatcher = Objects.requireNonNull(fileWatcher, "FileWatcher must not be null");
this.cachedConfig.set(loadConfigOrDefault());
this.lastModified = configFile.lastModified();
this.fileWatcher.start(this::onFileChanged);
}
// Factory method for convenience
public static DynamicConfig fromPath(String dir, String fileName) {
File configFile = new File(dir, fileName);
if (!configFile.exists()) {
throw new IllegalArgumentException("Config file does not exist: " + configFile.getAbsolutePath());
}
return new DynamicConfig(configFile, new NioConfigFileWatcher(configFile));
}
public Config getConfig() {
long currentLastModified = configFile.lastModified();
if (currentLastModified > lastModified) {
logger.info("Config file changed, reloading...");
reloadConfig();
}
return cachedConfig.get();
}
private void reloadConfig() {
Config newConfig = loadConfigOrDefault();
cachedConfig.set(newConfig);
lastModified = configFile.lastModified();
}
private Config loadConfigOrDefault() {
try {
Config config = ConfigFactory.parseFile(configFile).resolve();
logger.info("Loaded config from {}", configFile.getAbsolutePath());
return config;
} catch (Exception e) {
logger.error("Failed to load config, using last known good config", e);
Config fallback = cachedConfig.get();
return fallback != null ? fallback : ConfigFactory.empty();
}
}
private void onFileChanged() {
lastModified = 0; // Force reload on next access
}
@Override
public void close() throws IOException {
fileWatcher.close();
logger.info("DynamicConfig closed.");
}
}
What is DynamicConfig?
DynamicConfig is a Java class that:
- Loads your configuration file (like
.conf,.json, or.properties) - Watches the file for changes using a file watcher
- Automatically reloads the config when the file changes
- Always gives you the latest config when you call
getConfig()
Step 4: Creating FileWatcher class
package com.raju.codekatas.configsync.watcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
public class NioConfigFileWatcher implements ConfigFileWatcher {
private static final Logger logger = LoggerFactory.getLogger(NioConfigFileWatcher.class);
private final File configFile;
public Thread watcherThread;
private volatile boolean running = true;
public NioConfigFileWatcher(File configFile) {
this.configFile = configFile;
}
@Override
public void start(Runnable onChange) {
watcherThread = new Thread(() -> {
Path path = configFile.toPath().getParent();
String fileName = configFile.getName();
try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
while (running) {
WatchKey key = watchService.take();
for (WatchEvent<?> event : key.pollEvents()) {
Path changed = (Path) event.context();
if (changed.getFileName().toString().equals(fileName)) {
logger.info("Detected change in {}", fileName);
onChange.run();
}
}
key.reset();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.info("File watcher thread interrupted, shutting down.");
} catch (IOException e) {
logger.error("Error watching config file", e);
}
}, "ConfigFileWatcher");
watcherThread.setDaemon(true);
watcherThread.start();
}
@Override
public void close() {
running = false;
if (watcherThread != null) {
watcherThread.interrupt();
}
logger.info("ConfigFileWatcher stopped.");
}
}
How Does the File Watcher Work?
The file watcher uses Java’s WatchService API to monitor a directory for changes.
When you edit and save your config file, the watcher detects the change and tells DynamicConfig to reload the file.
Step 5: Using DynamicConfig in Your Application
package com.raju.codekatas.configsync;
import com.raju.codekatas.configsync.config.DynamicConfig;
import com.typesafe.config.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Scanner;
public class ConfigLoaderExample {
private static final Logger logger = LoggerFactory.getLogger(ConfigLoaderExample.class);
public static void main(String[] args) throws Exception {
// Start DynamicConfig
DynamicConfig dynamicConfig = DynamicConfig.fromPath("src/main/resources", "test.conf");
logger.info("App is running. Edit test.conf and type 'show' to see updated values.");
Scanner scanner = new Scanner(System.in);
while (true) {
logger.info("Type 'show' to display config, or 'exit' to quit: ");
String input = scanner.nextLine();
if ("exit".equalsIgnoreCase(input)) {
break;
} else if ("show".equalsIgnoreCase(input)) {
Config config = dynamicConfig.getConfig();
String name = config.getString("app.name");
String version = config.getString("app.version");
boolean enabled = config.getBoolean("app.enabled");
int maxConnections = config.getInt("app.maxConnections");
logger.info("Current Config:");
logger.info("Name: {}", name);
logger.info("Version: {}", version);
logger.info("Enabled: {}", enabled);
logger.info("Max Connections: {}", maxConnections);
}
}
dynamicConfig.close();
}
}
Step-by-Step Testing Instructions
1. Prepare Your Config File
- Make sure you have a file named
test.confinsrc/main/resourceswith content like:
app {
name = "TestApp"
version = "1.0.0"
enabled = true
maxConnections = 10
}
2. Run the Program
- Run the
ConfigLoaderExampleclass from your IDE or command line. - You should see a log message:
App is running. Edit test.conf and type 'show' to see updated values.
3. Display the Current Config
- In the console, type
showand press Enter. - The program will log the current config values, for example:
Loaded config from /Users/rmethuku/Raju/pocs/code-katas/src/main/resources/test.conf
App is running. Edit test.conf and type 'show' to see updated values.
Type 'show' to display config, or 'exit' to quit:
Current Config:
Name: TestApp12
Version: 1.0.0
Enabled: true
Max Connections: 10
Type 'show' to display config, or 'exit' to quit:
4. Edit the Config File While the App is Running
- Open
src/main/resources/test.confin a text editor. - Change a value, for example:
app {
name = "MyNewApp"
version = "2.0.0"
enabled = false
maxConnections = 20
}
- Save the file.
5. Fetch the Updated Config
- Go back to your running program.
- Type
showagain and press Enter. - The program will now log the updated values:
Current Config:
Name: MyNewApp
Version: 2.0.0
Enabled: false
Max Connections: 20
6. Exit the Program
- Type
exitand press Enter to stop the program.
What’s Happening Behind the Scenes?
DynamicConfigis watching your config file for changes.- When you save the file, the watcher detects the change and marks the config as “stale.”
- The next time you call
getConfig()(by typingshow), it reloads the file and gives you the latest values. - You never need to restart your app to pick up config changes!
Advanced Topics
Handling Different File Formats
Our solution works with multiple formats out of the box thanks to Typesafe Config:
JSON Example (config.json):
{
"app": {
"name": "TestApp",
"version": "1.0.0",
"enabled": true,
"maxConnections": 10
}
}
Properties Example (config.properties):
app.name=TestApp
app.version=1.0.0
app.enabled=true
app.maxConnections=10
Performance Considerations
- The file watcher uses OS-level notifications, so it’s very efficient
- Configs are only reloaded when actually needed (lazy loading)
- The AtomicReference ensures thread-safe access
Error Handling Strategies
Our implementation has several safety nets:
- Keeps last known good config if new one fails to load
- Logs errors for debugging
- Uses atomic references to prevent partial updates
Common Pitfalls and Solutions
Problem: Changes aren’t being detected
- Solution: Make sure you’re saving the file properly. Some editors save to temporary files first.
Problem: Getting old values after update
- Solution: The config is only reloaded when you call
getCurrentConfig(). Make sure you're not caching values yourself.
Problem: Too many reloads when saving
- Solution: Some editors trigger multiple save events. You can add a short delay before reloading.
Real-World Enhancements
For production use, you might want to add:
- Metrics to track how often config changes
- Notification system to alert when config changes
- Validation rules for config values
- Support for remote config files (HTTP/S3)
Conclusion
Congratulations! You’ve now built a professional-grade configuration system that:
- Dynamically reloads changes
- Handles errors gracefully
- Works with multiple file formats
- Is thread-safe and efficient
This is exactly the kind of feature that separates amateur projects from professional ones. With this in your toolkit, you’re ready to build more robust, maintainable Java applications.
Remember: Great software adapts to change without skipping a beat. Now your applications can too!
Next Steps
- Try adding support for environment variable overrides
- Experiment with different config file formats
- Extend the system to watch multiple config files
Coming Up Next: Dynamic Configuration Reload in Spring Boot!
Watch this space for my next post, where we’ll explore how to implement this same dynamic configuration reloading functionality in Spring Boot applications!
While our current Java implementation works great for standard applications, Spring Boot offers some powerful built-in features that can make this process even smoother. We’ll cover:
- How Spring’s
@RefreshScopeworks - Using Spring Cloud Config for centralized configuration
- The magic of the
/actuator/refreshendpoint - Comparing our custom solution with Spring’s approach
Which would you like me to focus on first? Let me know in the comments!
Pro Tip: Bookmark this post so you can compare both approaches once the Spring version is live. You’ll be amazed at how differently these two solutions tackle the same problem!
👋 Let’s Connect!
If you found this post insightful, here’s how you can help spread the knowledge:
👏 Clap if you enjoyed it — your claps motivate me to keep sharing more Java tricks and insights! 🔗 Share this post with your network so others can learn too. 💬 Ask your questions or share your experiences in the comments. Have you encountered this situation? Let’s discuss!
🚀 Follow me for more deep dives into Java, design patterns, and programming gotchas! Let’s learn and grow together. 🌟
메타데이터
- post_id
- 60fb16b86df4
- slug
- java-scenario-based-interview-question-5-how-to-dynamically-reload-configuration-files-in-60fb16b86df4
- url
- https://medium.com/@narasimha4789/java-scenario-based-interview-question-5-how-to-dynamically-reload-configuration-files-in-60fb16b86df4
- canonical_url
- https://medium.com/@narasimha4789/java-scenario-based-interview-question-5-how-to-dynamically-reload-configuration-files-in-60fb16b86df4
- author_url
- https://medium.com/@narasimha4789
- status
- ok
- fetched_at
- 2026-08-06 07:53:32