中間件 ZK分佈式專題與Dubbo微服務入門 7-8 curator之PathChildrenCache子節點監聽

0    課程地址

https://coding.imooc.com/lesson/201.html#mid=12737

 

1    重點關注

1.1    本節內容

curator自帶節點監聽多次,監聽子節點(可以針對增刪改不同類型的節點修改類型判斷)

 

1.2    關鍵代碼

// 爲子節點添加watcher
        // PathChildrenCache: 監聽數據節點的增刪改,會觸發事件
        String childNodePathCache =  nodePath;
        // cacheData: 設置緩存節點的數據狀態
        final PathChildrenCache childrenCache = new PathChildrenCache(cto.client, childNodePathCache, true);
        /**
         * StartMode: 初始化方式
         * POST_INITIALIZED_EVENT:異步初始化,初始化之後會觸發事件,這個經常使用
         * NORMAL:異步初始化 這個不常用,更多的異步處理需要觸發事件
         * BUILD_INITIAL_CACHE:同步初始化,這個用的較少,同步無法觸發事件
         */
        childrenCache.start(StartMode.POST_INITIALIZED_EVENT);
        
        List<ChildData> childDataList = childrenCache.getCurrentData();
        System.out.println("當前數據節點的子節點數據列表:");
        for (ChildData cd : childDataList) {
            String childData = new String(cd.getData());
            System.out.println(childData);
        }
        // 根據event.getType判斷節點變化類型
        childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                if(event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)){
                    System.out.println("子節點初始化ok...");
                }
                // 這裏的數據路徑,通常可以從配置平臺和環境變量獲取,匹配到對應節點只能對特定文件生效
                else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)){
                    String path = event.getData().getPath();
                    if (path.equals(ADD_PATH)) {
                        System.out.println("添加子節點:" + event.getData().getPath());
                        System.out.println("子節點數據:" + new String(event.getData().getData()));
                    } else if (path.equals("/super/imooc/e")) {
                        System.out.println("添加不正確...");
                    }
                    
                }else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)){
                    System.out.println("刪除子節點:" + event.getData().getPath());
                }else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    System.out.println("修改子節點路徑:" + event.getData().getPath());
                    System.out.println("修改子節點數據:" + new String(event.getData().getData()));
                }
            }
        });
        
        Thread.sleep(1000000);
        
        cto.closeZKClient();
        boolean isZkCuratorStarted2 = cto.client.isStarted();
        System.out.println("當前客戶的狀態:" + (isZkCuratorStarted2 ? "連接中" : "已關閉"));
    }
    
    public final static String ADD_PATH = "/super/imooc/d";
    

 

 

 

 

2    課程內容


 

 


 

3    Coding

3.1    Curator使用監聽(可判斷節點變更類型)

  • 啓動服務端
    進入到
cd /usr/local/zookeeper/bin

 
    重啓zookeeper服務端
./zkServer.sh restart

 

  • 主類
package com.imooc.curator;

import java.util.List;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;

public class CuratorOperator {

    public CuratorFramework client = null;
    public static final String zkServerPath = "172.26.139.4:2181";

    /**
     * 實例化zk客戶端
     */
    public CuratorOperator() {
        /**
         * 同步創建zk示例,原生api是異步的
         * 
         * curator鏈接zookeeper的策略:ExponentialBackoffRetry
         * baseSleepTimeMs:初始sleep的時間
         * maxRetries:最大重試次數
         * maxSleepMs:最大重試時間
         */
//        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 5);
        
        /**
         * curator鏈接zookeeper的策略:RetryNTimes
         * n:重試的次數
         * sleepMsBetweenRetries:每次重試間隔的時間
         */
        RetryPolicy retryPolicy = new RetryNTimes(3, 5000);
        
        /**
         * curator鏈接zookeeper的策略:RetryOneTime
         * sleepMsBetweenRetry:每次重試間隔的時間
         */
//        RetryPolicy retryPolicy2 = new RetryOneTime(3000);
        
        /**
         * 永遠重試,不推薦使用
         */
//        RetryPolicy retryPolicy3 = new RetryForever(retryIntervalMs)
        
        /**
         * curator鏈接zookeeper的策略:RetryUntilElapsed
         * maxElapsedTimeMs:最大重試時間
         * sleepMsBetweenRetries:每次重試間隔
         * 重試時間超過maxElapsedTimeMs後,就不再重試
         */
//        RetryPolicy retryPolicy4 = new RetryUntilElapsed(2000, 3000);
        
        client = CuratorFrameworkFactory.builder()
                .connectString(zkServerPath)
                .sessionTimeoutMs(10000).retryPolicy(retryPolicy)
                .namespace("workspace").build();
        client.start();
    }
    
    /**
     * 
     * @Description: 關閉zk客戶端連接
     */
    public void closeZKClient() {
        if (client != null) {
            this.client.close();
        }
    }
    
    public static void main(String[] args) throws Exception {
        // 實例化
        CuratorOperator cto = new CuratorOperator();
        boolean isZkCuratorStarted = cto.client.isStarted();
        System.out.println("當前客戶的狀態:" + (isZkCuratorStarted ? "連接中" : "已關閉"));
        
        // 創建節點
        String nodePath = "/super/imooc";
//        byte[] data = "superme".getBytes();
//        cto.client.create().creatingParentsIfNeeded()
//            .withMode(CreateMode.PERSISTENT)
//            .withACL(Ids.OPEN_ACL_UNSAFE)
//            .forPath(nodePath, data);
        
        // 更新節點數據
//        byte[] newData = "batman".getBytes();
//        cto.client.setData().withVersion(0).forPath(nodePath, newData);
        
        // 刪除節點
//        cto.client.delete()
//                  .guaranteed()                    // 如果刪除失敗,那麼在後端還是繼續會刪除,直到成功
//                  .deletingChildrenIfNeeded()    // 如果有子節點,就刪除
//                  .withVersion(0)
//                  .forPath(nodePath);
        
        
        
        // 讀取節點數據
//        Stat stat = new Stat();
//        byte[] data = cto.client.getData().storingStatIn(stat).forPath(nodePath);
//        System.out.println("節點" + nodePath + "的數據爲: " + new String(data));
//        System.out.println("該節點的版本號爲: " + stat.getVersion());
        
        
        // 查詢子節點
//        List<String> childNodes = cto.client.getChildren()
//                                            .forPath(nodePath);
//        System.out.println("開始打印子節點:");
//        for (String s : childNodes) {
//            System.out.println(s);
//        }
        
                
        // 判斷節點是否存在,如果不存在則爲空
//        Stat statExist = cto.client.checkExists().forPath(nodePath + "/abc");
//        System.out.println(statExist);
        
        
        // watcher 事件  當使用usingWatcher的時候,監聽只會觸發一次,監聽完畢後就銷燬
//        cto.client.getData().usingWatcher(new MyCuratorWatcher()).forPath(nodePath);
//        cto.client.getData().usingWatcher(new MyWatcher()).forPath(nodePath);
        
        // 爲節點添加watcher
        // NodeCache: 監聽數據節點的變更,會觸發事件
//        final NodeCache nodeCache = new NodeCache(cto.client, nodePath);
//        // buildInitial : 初始化的時候獲取node的值並且緩存
//        nodeCache.start(true);
//        if (nodeCache.getCurrentData() != null) {
//            System.out.println("節點初始化數據爲:" + new String(nodeCache.getCurrentData().getData()));
//        } else {
//            System.out.println("節點初始化數據爲空...");
//        }
//        nodeCache.getListenable().addListener(new NodeCacheListener() {
//            public void nodeChanged() throws Exception {
//                if (nodeCache.getCurrentData() == null) {
//                    System.out.println("空");
//                    return;
//                }
//                String data = new String(nodeCache.getCurrentData().getData());
//                System.out.println("節點路徑:" + nodeCache.getCurrentData().getPath() + "數據:" + data);
//            }
//        });
        
        
        // 爲子節點添加watcher
        // PathChildrenCache: 監聽數據節點的增刪改,會觸發事件
        String childNodePathCache =  nodePath;
        // cacheData: 設置緩存節點的數據狀態
        final PathChildrenCache childrenCache = new PathChildrenCache(cto.client, childNodePathCache, true);
        /**
         * StartMode: 初始化方式
         * POST_INITIALIZED_EVENT:異步初始化,初始化之後會觸發事件
         * NORMAL:異步初始化
         * BUILD_INITIAL_CACHE:同步初始化
         */
        childrenCache.start(StartMode.POST_INITIALIZED_EVENT);
        
        List<ChildData> childDataList = childrenCache.getCurrentData();
        System.out.println("當前數據節點的子節點數據列表:");
        for (ChildData cd : childDataList) {
            String childData = new String(cd.getData());
            System.out.println(childData);
        }
        
        childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
                if(event.getType().equals(PathChildrenCacheEvent.Type.INITIALIZED)){
                    System.out.println("子節點初始化ok...");
                }
                
                else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_ADDED)){
                    String path = event.getData().getPath();
                    if (path.equals(ADD_PATH)) {
                        System.out.println("添加子節點:" + event.getData().getPath());
                        System.out.println("子節點數據:" + new String(event.getData().getData()));
                    } else if (path.equals("/super/imooc/e")) {
                        System.out.println("添加不正確...");
                    }
                    
                }else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)){
                    System.out.println("刪除子節點:" + event.getData().getPath());
                }else if(event.getType().equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)){
                    System.out.println("修改子節點路徑:" + event.getData().getPath());
                    System.out.println("修改子節點數據:" + new String(event.getData().getData()));
                }
            }
        });
        
        Thread.sleep(1000000);
        
        cto.closeZKClient();
        boolean isZkCuratorStarted2 = cto.client.isStarted();
        System.out.println("當前客戶的狀態:" + (isZkCuratorStarted2 ? "連接中" : "已關閉"));
    }
    
    public final static String ADD_PATH = "/super/imooc/d";
    
}

 

  • linux客戶端修改節點(修改多次)
--啓動linux客戶端
zkCli.sh

--初始化節點
[zk: localhost:2181(CONNECTED) 2] create /workspace/super/imooc/d d
Created /workspace/super/imooc/d
[zk: localhost:2181(CONNECTED) 3] create /workspace/super/imooc/a a
Created /workspace/super/imooc/a
[zk: localhost:2181(CONNECTED) 4] create /workspace/super/imooc/b b
Created /workspace/super/imooc/b
[zk: localhost:2181(CONNECTED) 5] create /workspace/super/imooc/c c
Created /workspace/super/imooc/c
[zk: localhost:2181(CONNECTED) 6] ls /workspace/super/imooc        
[a, b, c, d]

--啓動sts客戶端後,進行修改節點
[zk: localhost:2181(CONNECTED) 7] set /workspace/super/imooc/d ddd
cZxid = 0x101
ctime = Wed Apr 10 06:32:42 CST 2024
mZxid = 0x106
mtime = Wed Apr 10 06:34:50 CST 2024
pZxid = 0x101
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0
[zk: localhost:2181(CONNECTED) 8] set /workspace/super/imooc/a aaa
cZxid = 0x102
ctime = Wed Apr 10 06:32:47 CST 2024
mZxid = 0x107
mtime = Wed Apr 10 06:35:04 CST 2024
pZxid = 0x102
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 3
numChildren = 0

--啓動sts客戶端後,進行刪除節點
[zk: localhost:2181(CONNECTED) 9] delete /workspace/super/imooc/d  

--啓動sts客戶端後,進行創建節點
[zk: localhost:2181(CONNECTED) 10] create /workspace/super/imooc/d
[zk: localhost:2181(CONNECTED) 11] create /workspace/super/imooc/d d2
Created /workspace/super/imooc/d
[zk: localhost:2181(CONNECTED) 12] create /workspace/super/imooc/a a2
Node already exists: /workspace/super/imooc/a


--啓動sts客戶端後,驗證不同目錄操作打印
[zk: localhost:2181(CONNECTED) 13] create /workspace/super/imooc/e e2
Created /workspace/super/imooc/e

 

  • 打印日誌(監聽多次)
2024-04-10 06:34:34,150 [main] [org.apache.zookeeper.Environment.logEnv(Environment.java:100)] - [INFO] Client environment:os.version=10.0
2024-04-10 06:34:34,151 [main] [org.apache.zookeeper.Environment.logEnv(Environment.java:100)] - [INFO] Client environment:user.name=18612
2024-04-10 06:34:34,152 [main] [org.apache.zookeeper.Environment.logEnv(Environment.java:100)] - [INFO] Client environment:user.home=C:\Users\18612
2024-04-10 06:34:34,153 [main] [org.apache.zookeeper.Environment.logEnv(Environment.java:100)] - [INFO] Client environment:user.dir=D:\project\xin\zk_sts_imooc\imooc-zk-curator-maven
2024-04-10 06:34:34,153 [main] [org.apache.zookeeper.ZooKeeper.<init>(ZooKeeper.java:441)] - [INFO] Initiating client connection, connectString=172.26.139.4:2181 sessionTimeout=10000 watcher=org.apache.curator.ConnectionState@595b007d
2024-04-10 06:34:34,365 [main] [org.apache.curator.framework.imps.CuratorFrameworkImpl.start(CuratorFrameworkImpl.java:326)] - [INFO] Default schema
當前客戶的狀態:連接中
2024-04-10 06:34:34,371 [main-SendThread(172.26.139.4:2181)] [org.apache.zookeeper.ClientCnxn$SendThread.logStartConnect(ClientCnxn.java:1035)] - [INFO] Opening socket connection to server 172.26.139.4/172.26.139.4:2181. Will not attempt to authenticate using SASL (unknown error)
2024-04-10 06:34:34,381 [main-SendThread(172.26.139.4:2181)] [org.apache.zookeeper.ClientCnxn$SendThread.primeConnection(ClientCnxn.java:877)] - [INFO] Socket connection established to 172.26.139.4/172.26.139.4:2181, initiating session
2024-04-10 06:34:34,389 [main-SendThread(172.26.139.4:2181)] [org.apache.zookeeper.ClientCnxn$SendThread.onConnected(ClientCnxn.java:1302)] - [INFO] Session establishment complete on server 172.26.139.4/172.26.139.4:2181, sessionid = 0x1003feb17e7000d, negotiated timeout = 10000
當前數據節點的子節點數據列表:
2024-04-10 06:34:34,397 [main-EventThread] [org.apache.curator.framework.state.ConnectionStateManager.postState(ConnectionStateManager.java:237)] - [INFO] State change: CONNECTED
添加子節點:/super/imooc/d
子節點數據:d
子節點初始化ok...
修改子節點路徑:/super/imooc/d
修改子節點數據:ddd
修改子節點路徑:/super/imooc/a
修改子節點數據:aaa
刪除子節點:/super/imooc/d
添加子節點:/super/imooc/d
子節點數據:d2
添加不正確...

 




 

 










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章