一直很好奇soul中基於zookeeper的數據變動是如何作到的。雖然看到了是基於zkClient的實現的,仍是想本身嘗試下node
首先新建一個maven項目,引入zkClientgit
<dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.10</version> </dependency>
嘗試着對zokkeeper中的數據和節點作一些改變,而這個改變就是Soul使用zookeeper中對於插件,選擇器和規則變化將其映射到zookeeper上的結果github
public class ZkClientTest { public static final String connect = "127.0.0.1:2181"; private static ZkClient zkClient = null; private static String nodePath = "/zkclient1"; private static String nodeChildPath = "/zkclient1/n1/n11/n111/n1111"; public static void main(String[] args) throws Exception{ //初始化 init(connect,5000); //訂閱節點數據改變或者子節點變化,只須要訂閱一次,即可以一直使用。而原生zookeeper的監聽是一次性的,須要重複註冊。 subscribe(); //新增 create(nodePath,"n1"); //遞歸新增 createRecursion(nodeChildPath,"n1"); //查詢 query(nodePath); //修改 update(nodePath,"n11"); //單個節點刪除 // delete(nodePath); //遞歸刪除 deleteRecursion(nodePath); Thread.sleep(5000); } private static void deleteRecursion(String path) { boolean result = zkClient.deleteRecursive(path); System.out.println("delete:"+"["+path+"],result:"+result); } private static void delete(String path) { boolean result = zkClient.delete(path); System.out.println("delete:"+"["+path+"],result:"+result); } private static void update(String path, String data) { zkClient.writeData(path, data); System.out.println(); //System.out.println("setData:"+"["+path+"],stat:"+stat); } private static void query(String path) { Object o = zkClient.readData(path); System.out.println("query:"+"["+path+"],result:"+o); } private static void createRecursion(String path,String data) { zkClient.createPersistent(path,true); System.out.println("create:"+"["+path+"-->"+data); } private static void create(String path, String data) { boolean exists = zkClient.exists(path); if(exists){ System.out.println("節點["+path+"]已存在,不能新增"); return; } String result = zkClient.create(path, data, CreateMode.PERSISTENT); System.out.println("create:"+"["+path+"-->"+data+"],result:"+result); } private static void subscribe() { //訂閱節點內容改變 zkClient.subscribeDataChanges(nodePath, new IZkDataListener() { public void handleDataChange(String dataPath, Object data) throws Exception { System.out.println("handleDataChange----->"+dataPath+"|"+data); } public void handleDataDeleted(String dataPath) throws Exception { System.out.println("handleDataDeleted----->"+dataPath); } } ); //訂閱子節點改變 zkClient.subscribeChildChanges(nodePath, new IZkChildListener() { public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception { System.out.println("handleChildChange----->"+parentPath+"|"+currentChilds); } }); } private static void init(String connect, int sessionTimeout) { zkClient = new ZkClient(connect, sessionTimeout); } }
具體的日誌表現以下圖所示
而在具體的zKclient類中能夠看到,zkclient其實是維護了一個while循環用來監聽數據以及節點的變化
這就是Soul在ZookeeperDataChangedListener實際使用的具體的時候的具體使用的方案
面試
nacos的監聽與zk相似,soul中的nacos一開始就監聽了soul各個層級的數據的變化編程
/** * Start. */ public void start() { watcherData(PLUGIN_DATA_ID, this::updatePluginMap); watcherData(SELECTOR_DATA_ID, this::updateSelectorMap); watcherData(RULE_DATA_ID, this::updateRuleMap); watcherData(META_DATA_ID, this::updateMetaDataMap); watcherData(AUTH_DATA_ID, this::updateAuthMap); }
而後經過函數式編程的方式將數據經過各個方法更新到緩存中小程序
protected void watcherData(final String dataId, final OnChange oc) { Listener listener = new Listener() { @Override public void receiveConfigInfo(final String configInfo) { oc.change(configInfo); } @Override public Executor getExecutor() { return null; } }; oc.change(getConfigAndSignListener(dataId, listener)); LISTENERS.getOrDefault(dataId, new ArrayList<>()).add(listener); }
這裏的最關鍵是Listener接口的獲取配置信息的兩個方法。能夠看到這個便是經過預先定義號的元數據id,規則id來進行監聽數據是否發生變化的緩存
上面就是nacos和zookeeper監聽數據變化的過程,如今能夠想到。無論是配置中心或者註冊中心。數據變化的監聽都是有必要的,能夠爲使用的應用作出跟隨配置改變而改變應用邏輯的能力。這也是Soul網關中很重要的一項能力微信
歡迎搜索關注本人與朋友共同開發的微信面經小程序【大廠面試助手】和公衆號【微瞰技術】,以及總結的分類面試題https://github.com/zhendiao/JavaInterviewsession