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()...........