背景
在研究规则引擎时,如果规则以文件的形式存储,那么就需要监听指定的目录或文件来感知规则是否变化,进而进行加载。当然,在其他业务场景下,比如想实现配置文件的动态加载、日志文件的监听、FTP文件变动监听等都会遇到类似的场景。
本文给大家提供三种解决方案,并分析其中的利弊,建议收藏,以备不时之需。
方案一:定时任务 + File#lastModified
这个方案是最简单,最能直接想到的解决方案。通过定时任务,轮训查询文件的最后修改时间,与上一次进行对比。如果发生变化,则说明文件已经修改,进行重新加载或对应的业务逻辑处理。
在上篇文章《JDK的一个Bug,监听文件变更要小心了》中已经编写了具体的实例,并且也提出了其中的不足。
这里再把实例代码贴出来:
public class FileWatchDemo {
/**
* 上次更新时间
*/
public static long LAST_TIME = 0L;
public static void main(String[] args) throws IOException {
String fileName = "/Users/zzs/temp/1.txt";
// 创建文件,仅为实例,实践中由其他程序触发文件的变更
createFile(fileName);
// 执行2次
for (int i = 0; i < 2; i++) {
long timestamp = readLastModified(fileName);
if (timestamp != LAST_TIME) {
System.out.println("文件已被更新:" + timestamp);
LAST_TIME = timestamp;
// 重新加载,文件内容
} else {
System.out.println("文件未更新");
}
}
}
public static void createFile(String fileName) throws IOException {
File file = new File(fileName);
if (!file.exists()) {
boolean result = file.createNewFile();
System.out.println("创建文件:" + result);
}
}
public static long readLastModified(String fileName) {
File file = new File(fileName);
return file.lastModified();
}
}
对于文件低频变动的场景,这种方案实现简单,基本上可以满足需求。不过像上篇文章中提到的那样,需要注意Java 8和Java 9中File#lastModified的Bug问题。
但该方案如果用在文件目录的变化上,缺点就有些明显了,比如:操作频繁,效率都损耗在遍历、保存状态、对比状态上了,无法充分利用OS的功能。
方案二:WatchService
在Java 7中新增了java.nio.file.WatchService
,通过它可以实现文件变动的监听。WatchService是基于操作系统的文件系统监控器,可以监控系统所有文件的变化,无需遍历、无需比较,是一种基于信号收发的监控,效率高。
<