`
sunxboy
  • 浏览: 2840217 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Auto reload of configuration when any change happen

 
阅读更多

In this post, i am writing about a solution of very common problem. Every application has some configuration which is expected to be refreshed on every change in configuration file. Past approaches to solve this problem had consisted of having a Thread, which periodically poll for file change based on ‘last update time stamp’ of 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 for above problem. This may not be the best implementation, but it will surely give a very good start for your solution. I bet !!

Sections in this post

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

A brief overview of WatchService

A WatchService is 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 a of now: ENTRY_CREATEENTRY_DELETEENTRY_MODIFY and 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.

Writing our 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.

A sample implementation goes as below :

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);
	}
}

Introducing configuration change listener

Now when we have our basic wrapper for our in memory cache of configuration properties, we need a mechanism to reload this cache on run time, 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 file, it simply refresh the in memory cache of configuration.

The constructor of above listener takes only one parameter i.e. fully qualified path of 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.

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, 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 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 property file, properties loaded are refreshed and new property value is available to use. Good work done so far !!

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.

Happy Learning !!

分享到:
评论

相关推荐

    解决any change made in its configuration may be lost after reimport

    在idea中module setting的对language的设置,在maven重新reimport或者reload之后都会丢失,根本办法是更改pom文件中的build部分,source和target org.apache.maven.plugins maven-compiler-plugin 8 8 参考: ...

    Smart Auto Reload-crx插件

    语言:Bahasa Indonesia,Bahasa Melayu,Deutsch,English,English (UK),English (United States),Filipino,Français,Kiswahili,Nederlands,Norsk,Tiếng Việt,Türkçe,català,dansk,eesti,español,hrvatski,...

    Auto_Reload_Blender_addon:方便的自动重新加载图像纹理

    自动重新加载图像-Blender(2.80)插件方便的自动重新加载图像纹理只需一点方便的插件,即可在信息标题属性面板: 刷新混合文件的所有图像使用计时器来获取修改后的图像文件,并在需要时重新加载它们这两个操作都会...

    cssautoreload.zip

    css auto reload 一款 chrome 开发者插件。它可以在你编辑 css 的时候,自动在页面上重新载入最新的 css 文件, 以达到立即展现你刚刚做的改变的目的。特别适合在双屏环境下进行 web 前端开发,使你不必在编辑器和...

    自动重新加载IDT「Auto Reload IDT」-crx插件

    在选定的时间间隔或特定时间自动刷新页面。 在选定的秒数间隔或特定时间自动刷新页面。 支持语言:English

    auto-reload-page:按指定的时间间隔自动重新加载页面

    npm install auto-reload-page 用法 import autoReloadPage from "auto-reload-page" ; // Open url in a separate window and reload every 10 seconds autoReloadPage ( "https://www.ipcc.ch/" , 10000 ) ; 原料...

    css auto reload-crx插件

    English detail description: http://allenm.github.io/css-auto-reload/#en-versioncss auto reload 是一个web开发者工具,一款 chrome 插件。它可以在你改变了 css 的时候,自动在页面上重新载入这些 css 文件, ...

    SysTick定时器延时函数

    使用GD32的SysTick定时器来设计延时函数

    Autoreloader: Reload tab on file change (Win)-crx插件

    第2步:安装Chrome扩展名 - 在Chrome Store上搜索“autoreloader”并安装扩展名 第3步:使用“添加目录”按钮添加要监视的文件夹。 而已! 现在,随时添加新文件,更改或删除在您监视的文件夹中,您的活动选项卡将...

    LiveReload

    浏览器自动刷新插件, LiveReload for Sublime text3。

    LiveReload.zip

    这是livereload插件

    unity 热重载插件Hot Reload1.12.9

    unity 热重载插件 Hot Reload Edit Code Without Compiling 1.12.9

    livereload

    livereload 浏览器自动预览软件

    liveReload for mac

    LiveReload for mac是一款跨平台的软件,在 OS X、Windows 以及 Linux 下都能使用。运行LiveReload for mac后载入网站源代码所在的文件夹,这样它就会开始识别。

    Chrome LiveReload

    很多时候,我们修改网页代码都要手动刷新一下看看效果,多了就比较麻烦了,livereload正是一个可以在你修改了代码后实时进行页面刷新的应用. 目前支持Google Chrome浏览器,非常方便。

    自动加载器:文件更改时重新加载选项卡(Win)「Autoreloader: Reload tab on file change (Win)」-crx插件

    Autoreloader v0.0.1 如果文件更改,自动重新加载chrome选项卡 步骤1:安装文件监视器服务器 - 从https://github.com/autoreloader/autoreloader/blob/master/Setup.exe?raw=true下载setup.exe - 运行setup.exe 第...

    connect-livereload, 连接中间件以将livereload脚本添加到响应.zip

    connect-livereload, 连接中间件以将livereload脚本添加到响应 连接 livereload连接中间件以将livereload脚本添加到响应。 不需要浏览器插件。 如果你对浏览器插件感到满意,那么你不需要这个中间件。 安装npm ...

    LiveReload.rar

    利用vs code开发前端界面时,在谷歌浏览器自动刷新页面。

    chorme liveReload插件

    chorme liveReload 是chorme的一个插件 结合grunt 可实现实时刷新

Global site tag (gtag.js) - Google Analytics