HowToDoInJava

  • Python
  • Java
  • Spring Boot
  • Dark Mode
Home / Java 7 / Java WatchService Example to Auto Reload Properties

Java WatchService Example to Auto Reload Properties

Automatically refresh the configuration files whenever any change happens in those files – It is a very common problem seen in the most application. Every application has some configuration which is expected to be refreshed on every change in the configuration file. Past approaches to solve this problem had consisted of having a Thread, which periodically poll for file change based on the ‘last update timestamp‘ of the configuration file.

Now with Java 7, things have changed. Java 7 has introduced an excellent feature: WatchService. I will try to give you a potential solution to the above problem. This may not be the best implementation, but it will surely give a very good start for your solution. I bet !!

Table of Contents:

1) A brief overview of WatchService
2) Writing our configuration provider
3) Introducing configuration change listener
4) Testing our code
5) Key notes

1. Java WatchService API

A WatchService is the JDKs internal service which watches for changes on registered objects. These registered objects are necessarily the instances of Watchable interface. When registering the watchable instance with WatchService, we need to specify the kind of change events we are interested in.

There are four type of events as of now:

  1. ENTRY_CREATE,
  2. ENTRY_DELETE,
  3. ENTRY_MODIFY, and
  4. OVERFLOW.

You can read about these events in provided links.

WatchService interface extends Closeable interface, means service can be closed as and when required. Normally, it should be done using JVM provided shut down hooks.

2. Application Configuration Provider

A configuration provider is simply a wrapper for holding the set of properties in java,util.Properties instance. It also provides methods to get the configured properties using their KEY.

package testWatchService;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class ApplicationConfiguration {
	private final static ApplicationConfiguration INSTANCE = new ApplicationConfiguration();

	public static ApplicationConfiguration getInstance() {
		return INSTANCE;
	}

	private static Properties configuration = new Properties();

	private static Properties getConfiguration() {
		return configuration;
	}

	public void initilize(final String file) {
		InputStream in = null;
		try {
			in = new FileInputStream(new File(file));
			configuration.load(in);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public String getConfiguration(final String key) {
		return (String) getConfiguration().get(key);
	}

	public String getConfigurationWithDefaultValue(final String key,
			final String defaultValue) {
		return (String) getConfiguration().getProperty(key, defaultValue);
	}
}

3. Configuration Change Listener – File Watcher

Now when we have our basic wrapper for our in-memory cache of configuration properties, we need a mechanism to reload this cache on runtime, whenever configuration file stored in file system changes.

I have written a sample working code for your help:


package testWatchService;

import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;

public class ConfigurationChangeListner implements Runnable {
	private String configFileName = null;
	private String fullFilePath = null;

	public ConfigurationChangeListner(final String filePath) {
		this.fullFilePath = filePath;
	}

	public void run() {
		try {
			register(this.fullFilePath);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void register(final String file) throws IOException {
		final int lastIndex = file.lastIndexOf("/");
		String dirPath = file.substring(0, lastIndex + 1);
		String fileName = file.substring(lastIndex + 1, file.length());
		this.configFileName = fileName;

		configurationChanged(file);
		startWatcher(dirPath, fileName);
	}

	private void startWatcher(String dirPath, String file) throws IOException {
		final WatchService watchService = FileSystems.getDefault()
				.newWatchService();
		Path path = Paths.get(dirPath);
		path.register(watchService, ENTRY_MODIFY);

		Runtime.getRuntime().addShutdownHook(new Thread() {
			public void run() {
				try {
					watchService.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});

		WatchKey key = null;
		while (true) {
			try {
				key = watchService.take();
				for (WatchEvent<?> event : key.pollEvents()) {
					if (event.context().toString().equals(configFileName)) {
						configurationChanged(dirPath + file);
					}
				}
				boolean reset = key.reset();
				if (!reset) {
					System.out.println("Could not reset the watch key.");
					break;
				}
			} catch (Exception e) {
				System.out.println("InterruptedException: " + e.getMessage());
			}
		}
	}

	public void configurationChanged(final String file) {
		System.out.println("Refreshing the configuration.");
		ApplicationConfiguration.getInstance().initilize(file);
	}
}

Above class is created using a thread which will be listening to configuration properties file changes using WatchService.

Once, it detects any modification in the file, it simply refreshes the in-memory cache of configuration.

The constructor of the above listener takes only one parameter i.e. fully qualified path of the monitored configuration file. Listener class is notified immediately when configuration file is changed in file system.

This listener class then call ApplicationConfiguration.getInstance().initilize(file); to reload in memory cache.

4. Testing our code

Now, when we are ready with our classes, we will test them.

First of all, store a test.properties file with following content in 'C:/Lokesh/temp' folder.

TEST_KEY=TEST_VALUE

Now, let us test above classes using below code.

package testWatchService;

public class ConfigChangeTest {
	private static final String FILE_PATH = "C:/Lokesh/temp/test.properties";

	public static void main(String[] args) {
		ConfigurationChangeListner listner = new ConfigurationChangeListner(
				FILE_PATH);
		try {
			new Thread(listner).start();
			while (true) {
				Thread.sleep(2000l);
				System.out.println(ApplicationConfiguration.getInstance()
						.getConfiguration("TEST_KEY"));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

//Output of the above program (Change the TEST_VALUE to TEST_VALUE1 and TEST_VALUE2 using any file editor and save).

Refreshing the configuration.

TEST_VALUE

TEST_VALUE

TEST_VALUE

Refreshing the configuration.

TEST_VALUE1

Refreshing the configuration.

TEST_VALUE2

Above outputs show that every time we make any change to the property file, properties loaded are refreshed and new property value is available to use. Good work is done so far !!

5. Key notes

  1. If you are using Java 7 in your new project, and you are not using old-fashioned methods to reload your properties, you are not doing it rightly.
  2. WatchService provides two methods take() and poll(). While take() method wait for next change to happen and until it is blocked, poll() immediately check for change event.

    If nothing changed from last poll() call, it will return null. poll() method does not block the execution, so should be called in a Thread with some sleep time.

Drop me your questions/ suggestion in the comments area.

Happy Learning !!

Was this post helpful?

Let us know if you liked the post. That’s the only way we can improve.
TwitterFacebookLinkedInRedditPocket

About Lokesh Gupta

A family guy with fun loving nature. Love computers, programming and solving everyday problems. Find me on Facebook and Twitter.

Feedback, Discussion and Comments

  1. Rui Mota

    December 2, 2015

    Hi,
    why just I can’t use a thread/timer checking every second for properties file lastModified attribute and reload the properties if there are changes?
    What’s wrong with that?

  2. Ramachandran R

    October 20, 2015

    Hi,
    It’s very useful for properties. But my configuration is using json.config. ( “TEST_KEY”: TEST_VALUE). Can you please help me to do same.

  3. Dm.Romanstov

    February 4, 2015

    Hi! It’s very useful article for me, thank you!
    But I have some question. Would be grateful for the answer)

    Are “while (true)” is a good choice to cycle here?
    Is thread exist after close program (Spring-boot in my case)?
    Mb we must write something like this “while(Application.isActive())”?

    • Lokesh Gupta

      February 4, 2015

      This is just an example code and not intended to be used in prod environment. Please change it the way it is appropriate.

  4. gedassan

    April 24, 2014

    This was very helpful to me in 2014:)
    One thing that is nice about WatchService is that it extends Closeable, so it can be initiated with try-with-resources. And then you would not need the Runtime.getRuntime().addShutdownHook(new Thread()…

    • Lokesh Gupta

      April 24, 2014

      It’s good point.

  5. lalit

    December 16, 2013

    I am unable to modify the configuration file as long as program is running !!

  6. Brian

    August 2, 2013

    Thanks for the great article! One correction, you’ll want to call “configuration.clear()” before “configuration.load(in)”, load doesn’t clear out the existing keys so if you remove a key from your properties file it will still exist during the reloading of the properties unless you clear the existing values.

Comments are closed on this article!

Search Tutorials

Java 7 Tutorial

  • Java 7 – Feature Changes
  • Java 7 – Diamond Operator
  • Java 7 – String in Switch Statement
  • Java 7 – try-with-resources
  • Java 7 – Number Formatting
  • Java 7 – Suppressed Exceptions
  • Java 7 – Exception Handling
  • Java 7 – Fork/Join Framework
  • Java 7 – WatchService

Java Tutorial

  • Java Introduction
  • Java Keywords
  • Java Flow Control
  • Java OOP
  • Java Inner Class
  • Java String
  • Java Enum
  • Java Collections
  • Java ArrayList
  • Java HashMap
  • Java Array
  • Java Sort
  • Java Clone
  • Java Date Time
  • Java Concurrency
  • Java Generics
  • Java Serialization
  • Java Input Output
  • Java New I/O
  • Java Exceptions
  • Java Annotations
  • Java Reflection
  • Java Garbage collection
  • Java JDBC
  • Java Security
  • Java Regex
  • Java Servlets
  • Java XML
  • Java Puzzles
  • Java Examples
  • Java Libraries
  • Java Resources
  • Java 14
  • Java 12
  • Java 11
  • Java 10
  • Java 9
  • Java 8
  • Java 7

Meta Links

  • About Me
  • Contact Us
  • Privacy policy
  • Advertise
  • Guest and Sponsored Posts

Recommended Reading

  • 10 Life Lessons
  • Secure Hash Algorithms
  • How Web Servers work?
  • How Java I/O Works Internally?
  • Best Way to Learn Java
  • Java Best Practices Guide
  • Microservices Tutorial
  • REST API Tutorial
  • How to Start New Blog

Copyright © 2020 · HowToDoInjava.com · All Rights Reserved. | Sitemap

  • Sealed Classes and Interfaces