場景
系統實現中經常需要能夠感知配置文件的變化,然后及時更新上下文。
實現方案
- 自己起一個單獨線程,定時加載文件,實現較簡單,但是無法保證能夠實時捕捉文件變化,同時耗CPU
- 使用commons-io中的 FileAlterationObserver,思想和上面類似,對比前后文件列表的變化,觸發對應事件
- JDK 1.7提供的WatchService,利用底層文件系統提供的功能
使用 WatchService
WatchService用來監控一個目錄是否發生改變,但是可以通過 WatchEvent 上下文定位具體文件的變化。具體使用過程中要注意以下兩點:
- 文件改變可能會觸發兩次事件(我的理解:文件內容的變更,元數據的變更),可以通過文件的時間戳來控制
- 在文件變化事件發生后,如果立即讀取文件,可能所獲內容并不完整,建議的做法判斷文件的 length > 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
// 監控文件的變化,重新加載 executor.submit( new Runnable() { @Override public void run() { try { final Path path = FileSystems.getDefault().getPath(getMonitorDir()); System.out.println(path); final WatchService watchService = FileSystems.getDefault().newWatchService(); final WatchKey watchKey = path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY); while ( true ) { final WatchKey wk = watchService.take(); for (WatchEvent<?> event : wk.pollEvents()) { final Path changed = (Path) event.context(); Path absolute = path.resolve(changed); File configFile = absolute.toFile(); long lastModified = configFile.lastModified(); logger.info(lastModified + "----------------" ); // 利用文件時間戳,防止觸發兩次 if (changed.endsWith(getLicenseName()) && lastModified != LAST_MOD && configFile.length > 0 ) { logger.info( "----------------- reloading -----------------" ); LAST_MOD = lastModified; // 保存上一次時間戳 UPDATED = true ; // 設置標志位 } } if (UPDATED) { reloadFile(); // 重新加載 } // reset the key boolean valid = wk.reset(); if (!valid) { logger.error( "watch key invalid!" ); } } } catch (Exception e) { logger.error( "" ); } } }); |
參考
Watching a Directory for Changes
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://zhuanlan.zhihu.com/p/29089171