在需要熱加載配置、插件或緩存失效的場景下,監測文件最後修改時間是基礎需求。本文總結三種典型技術路線。
使用 java.util.Timer 定期檢查 file.lastModified()。
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
long last = 0;
@Override
public void run() {
long cur = file.lastModified();
if (cur > last) {
last = cur;
reload(); // 觸發重新加載
}
}
}, 0, 5000); // 每 5 秒檢查一次
簡單但精度受限於輪詢間隔;異常會殺死 Timer。
核心類 ManageClassLoader 維護 lastModified,讀取文件字節碼,通過 DynamicClassLoader.defineClass 重新定義類。
public Class<?> loadClass(String name) throws Exception {
if (isClassModified(name)) {
dc = new DynamicClassLoader();
return c = dc.findClass(getBytes(name));
}
return c;
}
private boolean isClassModified(String filename) {
File file = new File(filename);
if (file.lastModified() > lastModified) {
lastModified = file.lastModified();
return true;
}
return false;
}
適用於 .class 文件熱替換,注意類身份問題(同名類不同加載器視為不同類型)。
new Thread(() -> {
long last = 0;
while (!Thread.interrupted()) {
long cur = file.lastModified();
if (cur > last) {
last = cur;
onChange();
}
try { Thread.sleep(1000); } catch (InterruptedException e) { break; }
}
}).start();
靈活可控,支持優雅關閉(中斷線程),易於整合回調或事件總線。
FileAlterationMonitor、WatchService (JDK 7+) 基於操作系統原生通知(Linux inotify, Windows ReadDirectoryChangesW),無輪詢開銷,實時性最佳。FileSystemXmlApplicationContext 的 refresh() 或 Spring Boot DevTools 熱重載。| 方案 | 實時性 | 跨平台 | 複雜度 | 備註 |
|---|---|---|---|---|
| Timer/線程輪詢 | 間隔內 | 是 | 低 | 簡單場景 |
| 自定義類加載器 | 即時 | 是 | 高 | 類熱替換專用 |
| WatchService (NIO.2) | 即時 | 大多數 | 中 | 推薦生產環境 |