這種方式僅適合於比較小的項目,例如只有一兩台服務器,而且配置文件是可以直接修改的。例如Spring mvc 以war 包的形式部署,可以直接修改resources 中的配置文件。如果是Spring boot 項目,還想用這種方式的話,就要引用一個外部可以編輯的文件,比如一個固定的目錄,因為spring boot 大多數以jar 包部署,打到包裡的配置文件沒辦法直接修改。如果是比較大的項目,最好還是用配置中心,例如攜程的Apollo、Consul 等。
原始方式
原始方式指的是每次要修改配置的時候,都要重新打包發布或者重啟服務器。
假設我們用spring mvc 開發,開發完成後打成war 包部署到tomcat 上,如果這時我們修改一個短信接口地址。
我們要做如下操作:
1、打開配置文件,修改配置信息;
2、編譯打包;
3、停止tomcat ,刪除舊的項目目錄;
4、將新的war 包放到webapps ,啟動tomcat。
當然,可以直接在tomcat 中找到這個項目的配置文件,然後修改,但同樣需要重啟tomcat 。
如果只是單純做開發或者測試,除了有點浪費時間外,當然可以接受。那麼,既不想浪費時間又不想重啟tomcat 呢,有沒有辦法呢。這就輪到本文介紹的這種方式了。
WatchService 方式
Java 提供了WatchService 接口,這個接口是利用操作系統本身的文件監控器對目錄和文件進行監控,當被監控對象發生變化時,會有信號通知,從而可以高效的發現變化。
這種方式大致的原理:先根據操作系統new 一個監控器( WatchService ),然後選擇要監控的配置文件所在目錄或文件,然後訂閱要監控的事件,例如創建、刪除、編輯,最後向被監控位置註冊這個監控器。一旦觸發對應我們所訂閱的事件時,執行相應的邏輯即可。
先上代碼吧,這是在一個spring mvc 項目裡,監控的是resources 目錄。
@Repositorypublic class ConfigWatcher { private static final Logger logger = LoggerFactory.getLogger(ConfigWatcher.class); private static WatchService watchService; @PostConstruct public void init() { logger.info("啟動配置文件監控器"); try { watchService = FileSystems.getDefault().newWatchService(); URL url = ConfigWatcher.class.getResource("/"); Path path = Paths.get(url.toURI()); path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_CREATE); } catch (Exception e1) { e1.printStackTrace(); } /** * 啟動監控線程*/ Thread watchThread = new Thread(new WatchThread()); watchThread.setDaemon(true); watchThread.start(); /**註冊關閉鉤子*/ Thread hook = new Thread(new Runnable() { @Override public void run() { try { watchService.close(); } catch (IOException e) { e.printStackTrace(); } } }); Runtime.getRuntime().addShutdownHook(hook); } public class WatchThread implements Runnable { @Override public void run() { while (true) { try { // 嘗試獲取監控池的變化,如果沒有則一直等待WatchKey watchKey = watchService.take(); for (WatchEvent<?> event : watchKey.pollEvents()) { String editFileName = event.context().toString(); logger.info(editFileName); /** * 重新加載配置*/ } watchKey.reset();//完成一次監控就需要重置監控器一次} catch (Exception e) { e.printStackTrace(); } } } }}代碼非常簡單,一看就懂,在項目啟動的時候,用FileSystems.getDefault().newWatchService() 創建一個WatchService,這是根據操作系統來的。然後獲取resources 目錄的URL,並由此獲取Path,然後調用Path 對象的register 方法,註冊監控器,訂閱了編輯和創建事件。事件在StandardWatchEventKinds 類中定義,共有四種:
1、StandardWatchEventKinds#OVERFLOW
2、StandardWatchEventKinds#ENTRY_CREATE
3、StandardWatchEventKinds#ENTRY_DELETE
4、StandardWatchEventKinds#ENTRY_MODIFY
然後單獨啟動了一個WatchThread 線程來處理變化邏輯,在一個while 無限循環中調用take() 方法,直到有變化發生,一旦是我們監控的配置文件發生了變化,則調用我們的邏輯重新加載配置。另外,每次有變化發生後,要調用watchKey.reset() 方法來重置監控器。
最後,還要註冊一個hook,在jvm 關閉的時候可以關閉監控器。
有了這種方式,當我們有一些配置變化的時候,就可以直接到tomcat 下修改配置文件,不用重啟就可以生效了。
本文主要介紹的是這種方式,上面也說了,這種方式只適合非常簡單的項目,對於大型項目,就需要用到更高級的方式了。
配置中心的方式
當項目複雜度變高,配置修改後實時生效,灰度發布,分環境、分集群管理配置,完善的權限、審核機制可能都變成項目中要考慮的問題,這個時候,單純依賴配置文件就顯得力不從心了。
目前比較用的比較多的配置中心有etcd、zookeeper、disconf、Apollo 等。 disconf、Apollo 都是屬於拿來即用的,功能完善,而且有配套的UI。而etcd 和zookeeper 需要一些定制開發。
各位同學可以根據需要自行選擇,更詳細的內容可以自行搜索和實踐。