獲取修改時間
long lastTime = file.lastModified();
原文鏈接:https://blog.csdn.net/liuyueyi25/article/details/79292971
現在的問題時,我需要在這個文件的內容發生變動時,應用可以感知這種變動,並重新加載文件內容,更新應用內部緩存
一個最容易想到的方法,就是輪詢,判斷文件是否發生修改,如果修改了,則重新加載,並刷新內存,所以主要需要關心的問題如下:
如何輪詢?
如何判斷文件是否修改?
配置異常,會不會導致服務不可用?(即容錯,這個與本次主題關聯不大,但又比較重要…)
II. 設計與實現
問題抽象出來之后,對應的解決方案就比較清晰了
如何輪詢 ? –》 定時器 Timer, ScheduledExecutorService 都可以實現
如何判斷文件修改? –》根據 java.io.File#lastModified 獲取文件的上次修改時間,比對即可
進階方法
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
主要是借助這個工具中的 FileAlterationObserver, FileAlterationListener, FileAlterationMonitor 三個類來實現相關的需求場景了,當然使用也算是很簡單了,以至於都不太清楚可以再怎么去說明了,直接看下面從我的一個開源項目quick-alarm中拷貝出來的代碼
public class PropertiesConfListenerHelper { public static boolean registerConfChangeListener(File file, Function<File, Map<String, AlarmConfig>> func) { try { // 輪詢間隔 5 秒 long interval = TimeUnit.SECONDS.toMillis(5); // 因為監聽是以目錄為單位進行的,所以這里直接獲取文件的根目錄 File dir = file.getParentFile(); // 創建一個文件觀察器用於過濾 FileAlterationObserver observer = new FileAlterationObserver(dir, FileFilterUtils.and(FileFilterUtils.fileFileFilter(), FileFilterUtils.nameFileFilter(file.getName()))); //設置文件變化監聽器 observer.addListener(new MyFileListener(func)); FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer); monitor.start(); return true; } catch (Exception e) { log.error("register properties change listener error! e:{}", e); return false; } } static final class MyFileListener extends FileAlterationListenerAdaptor { private Function<File, Map<String, AlarmConfig>> func; public MyFileListener(Function<File, Map<String, AlarmConfig>> func) { this.func = func; } @Override public void onFileChange(File file) { Map<String, AlarmConfig> ans = func.apply(file); // 如果加載失敗,打印一條日志 log.warn("PropertiesConfig changed! reload ans: {}", ans); } } }
針對上面的實現,簡單說明幾點:
這個文件監聽,是以目錄為根源,然后可以設置過濾器,來實現對應文件變動的監聽
如上面registerConfChangeListener方法,傳入的file是具體的配置文件,因此構建參數的時候,撈出了目錄,撈出了文件名作為過濾
第二參數是jdk8語法,其中為具體的讀取配置文件內容,並映射為對應的實體對象
一個問題,如果 func方法執行時,也拋出了異常,會怎樣?
實際測試表現結果和上面一樣,拋出異常之后,依然跪,所以依然得注意,不要跑異常
那么簡單來看一下上面的實現邏輯,直接扣出核心模塊
public void run() { while(true) { if(this.running) { Iterator var1 = this.observers.iterator(); while(var1.hasNext()) { FileAlterationObserver observer = (FileAlterationObserver)var1.next(); observer.checkAndNotify(); } if(this.running) { try { Thread.sleep(this.interval); } catch (InterruptedException var3) { ; } continue; } } return; } }
IV. 小結
使用Java來實現配置文件變動的監聽,主要涉及到的就是兩個點
如何輪詢: 定時器(Timer, ScheduledExecutorService), 線程死循環+sleep
文件修改: File#lastModified
整體來說,這個實現還是比較簡單的,無論是自定義實現,還是依賴 commos-io來做,都沒太大的技術成本,但是需要注意的一點是:
千萬不要在定時任務 or 文件變動的回調方法中拋出異常!!!
為了避免上面這個情況,一個可以做的實現是借助EventBus的異步消息通知來實現,當文件變動之后,發送一個消息即可,然后在具體的重新加載文件內容的方法上,添加一個 @Subscribe注解即可,這樣既實現了解耦,也避免了異常導致的服務異常 (如果對這個實現有興趣的可以評論說明)
————————————————
版權聲明:本文為CSDN博主「一灰灰blog」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/liuyueyi25/article/details/79292971
————————————————
版權聲明:本文為CSDN博主「一灰灰blog」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/liuyueyi25/article/details/79292971