Java监听文件修改主流方式有三种:WatchService(推荐,事件驱动、高效)、Commons-IO的FileAlterationMonitor(轮询封装、开箱即用)、手动轮询lastModified(仅限调试或受限环境);回调须解耦并统一接口。

Java 中监听文件修改并触发回调,主流方式有三种:基于操作系统事件的 WatchService(推荐)、轻量级轮询(适合简单场景)、以及第三方库封装(如 JNotify 或 Commons-IO)。关键不在于“能不能”,而在于选对方案——既要准,又要稳,还要不拖慢主线程。
用 WatchService 监听目录变化(JDK 原生,推荐)
WatchService 是 Java NIO 提供的高效、事件驱动方案,底层调用系统 inotify(Linux)、kqueue(macOS)或 ReadDirectoryChangesW(Windows),无轮询开销,响应快且资源友好。
- 它监听的是目录,不是单个文件;需在回调中判断事件是否针对目标文件(例如只处理
config.yml) - 支持三种事件:
ENTRY_CREATE、ENTRY_MODIFY、ENTRY_DELETE;修改通常对应ENTRY_MODIFY,但注意:文本编辑器保存时可能先删后建,或写临时文件再重命名,建议同时关注ENTRY_CREATE和ENTRY_DELETE并结合文件名+最后修改时间双重校验 - 必须手动调用
key.reset(),否则后续事件不会到达;建议放在try-finally中防止中断丢失监听 - 监听器应运行在独立线程(如
new Thread(new DirectoryWatcher(...)).start()),避免阻塞主线程
用 Commons-IO 的 FileAlterationMonitor(封装友好,开箱即用)
如果你不想手写线程和事件循环,Apache Commons-IO 的 FileAlterationMonitor 提供了成熟的轮询封装,配置简单、容错性强,适合中小型项目快速集成。
- 依赖添加:
<groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version> - 核心是
FileAlterationObserver(指定目录 + 过滤器) +FileAlterationListener(自定义回调逻辑) - 轮询间隔可配(如 5 秒),适合对实时性要求不苛刻、但需兼容老旧环境(如某些容器内无法使用 inotify)的场景
- 自动处理文件重命名、临时文件覆盖等边界情况,比裸写
lastModified()更健壮
手动轮询 lastModified(最简,慎用于生产)
仅建议用于调试、脚本工具或嵌入式受限环境。原理是定时检查文件 lastModified() 时间戳是否变化。
立即学习“Java免费学习笔记(深入)”;
- 用
ScheduledExecutorService每隔固定周期执行比对,避免Timer的单线程缺陷和异常中断风险 - 仅靠时间戳不可靠:部分编辑器(如 VS Code)保存时可能不更新时间戳;NFS 或某些云盘同步延迟也会导致误判
- 务必加锁或原子变量保护上次记录时间,防止多线程读写冲突
- 必须加入异常兜底(如文件被占用、权限丢失),否则轮询线程崩溃会导致监听静默失效
回调设计要点(与监听解耦)
无论用哪种监听方式,回调逻辑都应与监听器本身分离,推荐定义标准接口:
public interface FileChangeCallback {
void onModified(Path file);
void onCreated(Path file);
void onDeleted(Path file);
default void onError(Throwable t) { /* 日志记录 */ }
}这样业务代码只需实现该接口,监听器内部统一调用,便于测试、复用和热替换。例如配置变更后刷新 Spring @ConfigurationProperties Bean,或重新加载规则引擎脚本。


















