jforum中使用Timer类定时监控配置文件是否发生了变化,如果发生了变化,则重新load一次配置文件。其中涉及到Timer类的使用,现将文件监控的代码从原项目中分离出来,供学习、参考只用。
1、工具类
package util;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
/**文件监控工具类**/
public class FileMonitor {
/**定时器**/
private Timer timer;
/**以文件名称为key,TimerTask为value**/
private Map timerEntries;
private static final FileMonitor instance = new FileMonitor();
private FileMonitor() {
this.timerEntries = new HashMap();
/**将先关的线程设置为非守护线程执行,否则程序会直接结束。
* JRE判断程序是否执行结束的标准是所有的前台线程执行完毕了,而不管后台线程的状态。
* jforum中设置为true,做为守护线程执行。但如果单独调用,必须设置为false,否则run方法不会执行。**/
this.timer = new Timer(false);
}
public static FileMonitor getInstance() {
return instance;
}
/**
* Add a file to the monitor
*
* @param listener
* The file listener
* @param filename
* The filename to watch
* @param period
* The watch interval.
*/
@SuppressWarnings("unchecked")
public void addFileChangeListener(FileChangeListener listener,
String filename, long period) {
/**将之前的监控取消掉**/
this.removeFileChangeListener(filename);
System.out.println("watch file---"+filename);
FileMonitorTask task = new FileMonitorTask(listener, filename);
this.timerEntries.put(filename, task);
/**计划任务,每隔一段时间检查文件的最后更新日期**/
this.timer.schedule(task, period, period);
}
/**
* Stop watching a file
*
* @param listener
* The file listener
* @param filename
* The filename to keep watch
*/
public void removeFileChangeListener(String filename) {
FileMonitorTask task = (FileMonitorTask) this.timerEntries.remove(filename);
if (task != null) {
task.cancel();
}
}
private static class FileMonitorTask extends TimerTask {
private FileChangeListener listener;
private String filename;
private File monitoredFile;
private long lastModified;
public FileMonitorTask(FileChangeListener listener, String filename) {
this.listener = listener;
this.filename = filename;
this.monitoredFile = new File(filename);
if (!this.monitoredFile.exists()) {
return;
}
this.lastModified = this.monitoredFile.lastModified();
}
public void run() {
System.out.println("run()...........");
/**表示文件最后一次被修改的时间的 long 值,
* 用该时间与历元(1970 年 1 月 1 日,00:00:00 GMT)的时间差来计算此值(以毫秒为单位)。**/
long latestChange = this.monitoredFile.lastModified();
// 如果日期发生变化,发生通知。
if (this.lastModified != latestChange) {
this.lastModified = latestChange;
this.listener.fileChanged(this.filename);
}
}
}
}
2、文件监听接口,定义一个文件监听的接口
package util;
public interface FileChangeListener
{
/**
* Invoked when a file changes
*
* @param filename Name of the changed file
* 定义一个接口,用来接受当文件发生更新时文件监视器FileMonitor发出的通知,并采取相应措施。
*/
public void fileChanged(String filename);
}
package util;
/*当全局属性文件SystemGlobals.properties发生变化时,重新加载。*/
public class SystemGlobalsListener implements FileChangeListener {
public void fileChanged(String filename) {
System.out.println("SystemGlobalsListener reload file");
}
}
测试代码
package test;
import java.io.FileInputStream;
import java.util.Properties;
import org.junit.BeforeClass;
import org.junit.Test;
import util.FileMonitor;
import util.SystemGlobalsListener;
public class TestListenForFile {
public static int fileChangesDelay;
@BeforeClass
public static void LoadFile() throws Exception{
FileInputStream fis = null;
Properties p = new Properties();
fis = new FileInputStream("your file path");
p.load(fis);
/**定时扫描文件的时间间隔**/
fileChangesDelay = Integer.parseInt((String)p.get("file.changes.delay"));
}
@Test
public static void testFileMonitor(){
if(fileChangesDelay > 0){
FileMonitor.getInstance().addFileChangeListener(new SystemGlobalsListener(),
"your file path",fileChangesDelay);
}
}
线程启动后,每隔一定时间自动检查文件的变更情况,在此过程中,修改文件,监听程序检查到文件最后一次修改的时间和之前的不一致时,会重新加载文件,打印日志如下:
run()...........
run()...........
run()...........
run()...........
run()...........
run()...........
SystemGlobalsListener reload file
run()...........
run()...........
run()...........
run()...........