ZooKeeper Watch Java API浅析getData

来源:互联网 发布:时序性数据库 编辑:程序博客网 时间:2024/06/05 21:06

        Watch是ZooKeeper中非常重要的一个机制,它可以监控ZooKeeper中节点的变化情况,告知客户端。下面,我们以代码为例来分析Watch在ZooKeeper中是如何实现的。ZooKeeper中一共由三种方法可以实现Watch,分别为getData、exists和getChildren,今天我们先来看下getData()方法:

        1、getData()

import java.io.IOException;import org.apache.zookeeper.CreateMode;import org.apache.zookeeper.KeeperException;import org.apache.zookeeper.WatchedEvent;import org.apache.zookeeper.Watcher;import org.apache.zookeeper.ZooKeeper;import org.apache.zookeeper.ZooDefs.Ids;public class TestZooKeeperWatcher {public static void main(String[] args) {ZooKeeper zk = null;try {System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("开始连接ZooKeeper...");// 创建与ZooKeeper服务器的连接zkString address = "192.168.1.226:2181";int sessionTimeout = 3000;zk = new ZooKeeper(address, sessionTimeout, new Watcher() {// 监控所有被触发的事件public void process(WatchedEvent event) {if (event.getType() == null || "".equals(event.getType())) {return;}System.out.println("已经触发了" + event.getType() + "事件!");}});System.out.println("ZooKeeper连接创建成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 创建根目录节点// 路径为/tmp_root_path// 节点内容为字符串"我是根目录/tmp_root_path"// 创建模式为CreateMode.PERSISTENTSystem.out.println("开始创建根目录节点/tmp_root_path...");zk.create("/tmp_root_path", "我是根目录/tmp_root_path".getBytes(),Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);System.out.println("根目录节点/tmp_root_path创建成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 创建第一个子目录节点// 路径为/tmp_root_path/childPath1// 节点内容为字符串"我是第一个子目录/tmp_root_path/childPath1"// 创建模式为CreateMode.PERSISTENTSystem.out.println("开始创建第一个子目录节点/tmp_root_path/childPath1...");zk.create("/tmp_root_path/childPath1","我是第一个子目录/tmp_root_path/childPath1".getBytes(),Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);System.out.println("第一个子目录节点/tmp_root_path/childPath1创建成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 创建第二个子目录节点// 路径为/tmp_root_path/childPath2// 节点内容为字符串"我是第二个子目录/tmp_root_path/childPath2"// 创建模式为CreateMode.PERSISTENTSystem.out.println("开始创建第二个子目录节点/tmp_root_path/childPath2...");zk.create("/tmp_root_path/childPath2","我是第二个子目录/tmp_root_path/childPath2".getBytes(),Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);System.out.println("第二个子目录节点/tmp_root_path/childPath2创建成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 获取第二个子目录节点/tmp_root_path/childPath2节点数据System.out.println("开始获取第二个子目录节点/tmp_root_path/childPath2节点数据...");System.out.println(new String(zk.getData("/tmp_root_path/childPath2", true, null)));System.out.println("第二个子目录节点/tmp_root_path/childPath2节点数据获取成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 修改第一个子目录节点/tmp_root_path/childPath1数据System.out.println("开始修改第一个子目录节点/tmp_root_path/childPath1数据...");zk.setData("/tmp_root_path/childPath1","我是修改数据后的第一个子目录/tmp_root_path/childPath1".getBytes(), -1);System.out.println("修改第一个子目录节点/tmp_root_path/childPath1数据成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 修改第二个子目录节点/tmp_root_path/childPath2数据System.out.println("开始修改第二个子目录节点/tmp_root_path/childPath2数据...");zk.setData("/tmp_root_path/childPath2","我是修改数据后的第二个子目录/tmp_root_path/childPath2".getBytes(), -1);System.out.println("修改第二个子目录节点/tmp_root_path/childPath2数据成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 删除第一个子目录节点System.out.println("开始删除第一个子目录节点/tmp_root_path/childPath1...");zk.delete("/tmp_root_path/childPath1", -1);System.out.println("第一个子目录节点/tmp_root_path/childPath1删除成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 删除第二个子目录节点System.out.println("开始删除第二个子目录节点/tmp_root_path/childPath2...");zk.delete("/tmp_root_path/childPath2", -1);System.out.println("第二个子目录节点/tmp_root_path/childPath2删除成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");// 删除根目录节点System.out.println("开始删除根目录节点/tmp_root_path...");zk.delete("/tmp_root_path", -1);System.out.println("根目录节点/tmp_root_path删除成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");} catch (IOException | KeeperException | InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {// 关闭连接if (zk != null) {try {zk.close();System.out.println("释放ZooKeeper连接成功!");} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}}
        通过以上示例可以看出,我们创建了一个根节点/tmp_root_path,并且在这个根节点下面创建了两个平级的子节点/tmp_root_path/childPath1和/tmp_root_path/childPath2,而我们中间加了一段代码,获取第二个子目录节点/tmp_root_path/childPath2节点数据调用zk的getData()方法时,第二个参数设置为true,即为监控第二个子节点/tmp_root_path/childPath2,执行结果如下:

............开始连接ZooKeeper...ZooKeeper连接创建成功!已经触发了None事件!............开始创建根目录节点/tmp_root_path...根目录节点/tmp_root_path创建成功!............开始创建第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1创建成功!........................开始创建第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2创建成功!............开始获取第二个子目录节点/tmp_root_path/childPath2节点数据...我是第二个子目录/tmp_root_path/childPath2第二个子目录节点/tmp_root_path/childPath2节点数据获取成功!............开始修改第一个子目录节点/tmp_root_path/childPath1数据...修改第一个子目录节点/tmp_root_path/childPath1数据成功!............开始修改第二个子目录节点/tmp_root_path/childPath2数据...已经触发了NodeDataChanged事件!修改第二个子目录节点/tmp_root_path/childPath2数据成功!............开始删除第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1删除成功!............开始删除第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2删除成功!............开始删除根目录节点/tmp_root_path...根目录节点/tmp_root_path删除成功!............释放ZooKeeper连接成功!
        可以发现,修改第二个子节点/tmp_root_path/childPath2数据时,触发了NodeDataChanged事件,而对应修改第一个子目录节点/tmp_root_path/childPath1数据,并没有触发该事件,并且,删除第二个子节点/tmp_root_path/childPath2时也没有触发!
        而当我们屏蔽到修改第二个子节点/tmp_root_path/childPath2数据相关代码时,屏蔽掉的部分和执行结果如下:

//// 修改第二个子目录节点/tmp_root_path/childPath2数据//System.out.println("开始修改第二个子目录节点/tmp_root_path/childPath2数据...");//zk.setData("/tmp_root_path/childPath2",//"我是修改数据后的第二个子目录/tmp_root_path/childPath2".getBytes(), -1);//System.out.println("修改第二个子目录节点/tmp_root_path/childPath2数据成功!");////Thread.currentThread().sleep(1000l);////System.out.println("...");//System.out.println("...");//System.out.println("...");//System.out.println("...");
............开始连接ZooKeeper...ZooKeeper连接创建成功!已经触发了None事件!............开始创建根目录节点/tmp_root_path...根目录节点/tmp_root_path创建成功!............开始创建第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1创建成功!........................开始创建第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2创建成功!............开始获取第二个子目录节点/tmp_root_path/childPath2节点数据...我是第二个子目录/tmp_root_path/childPath2第二个子目录节点/tmp_root_path/childPath2节点数据获取成功!............开始修改第一个子目录节点/tmp_root_path/childPath1数据...修改第一个子目录节点/tmp_root_path/childPath1数据成功!............开始删除第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1删除成功!............开始删除第二个子目录节点/tmp_root_path/childPath2...已经触发了NodeDeleted事件!第二个子目录节点/tmp_root_path/childPath2删除成功!............开始删除根目录节点/tmp_root_path...根目录节点/tmp_root_path删除成功!............释放ZooKeeper连接成功!
        执行结果显而易见,删除第二个子节点/tmp_root_path/childPath2时触发了NodeDataChanged事件,但是修改第一个子节点和删除第一个子节点并没有触发!

        我们再做一个变更,修改第二个子节点/tmp_root_path/childPath2两次,那么执行结果如何呢?添加的代码及执行结果如下:

// 第二次修改第二个子目录节点/tmp_root_path/childPath2数据System.out.println("开始第二次修改第二个子目录节点/tmp_root_path/childPath2数据...");zk.setData("/tmp_root_path/childPath2","我是第二次修改数据后的第二个子目录/tmp_root_path/childPath2".getBytes(), -1);System.out.println("第二次修改第二个子目录节点/tmp_root_path/childPath2数据成功!");Thread.currentThread().sleep(1000l);System.out.println("...");System.out.println("...");System.out.println("...");System.out.println("...");
............开始连接ZooKeeper...ZooKeeper连接创建成功!已经触发了None事件!............开始创建根目录节点/tmp_root_path...根目录节点/tmp_root_path创建成功!............开始创建第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1创建成功!........................开始创建第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2创建成功!............开始获取第二个子目录节点/tmp_root_path/childPath2节点数据...我是第二个子目录/tmp_root_path/childPath2第二个子目录节点/tmp_root_path/childPath2节点数据获取成功!............开始修改第一个子目录节点/tmp_root_path/childPath1数据...修改第一个子目录节点/tmp_root_path/childPath1数据成功!............开始修改第二个子目录节点/tmp_root_path/childPath2数据...已经触发了NodeDataChanged事件!修改第二个子目录节点/tmp_root_path/childPath2数据成功!............开始第二次修改第二个子目录节点/tmp_root_path/childPath2数据...第二次修改第二个子目录节点/tmp_root_path/childPath2数据成功!............开始删除第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1删除成功!............开始删除第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2删除成功!............开始删除根目录节点/tmp_root_path...根目录节点/tmp_root_path删除成功!............释放ZooKeeper连接成功!
        仅仅是第一次修改第二个子节点/tmp_root_path/childPath2数据时触发了NodeDataChanged事件,第二次修改与删除均未触发!

        而当我们在第二次修改第二个子节点/tmp_root_path/childPath2数据前先获取一遍,并且watch设置为true,那么两次对第二个子节点/tmp_root_path/childPath2数据的修改均会触发NodeDataChanged事件,并且获取根目录节点数据时,也仅是监控根目录,其子目录的变化不会触发NodeDataChanged事件,读者可自行尝试!


        结论:

        getData()方法仅仅监控对应节点的一次数据变化,无论是数据修改还是删除!若要每次对应节点发生变化都被监测到,那么每次都得先调用getData()方法获取一遍数据!

4 0
原创粉丝点击