ZooKeeper Watch Java API浅析getChildren

来源:互联网 发布:网络喷子为什么不治理 编辑:程序博客网 时间:2024/06/09 18:41

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

        3、getChildren

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;import org.apache.zookeeper.data.Stat;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("...");// 获取子目录节点列表System.out.println("开始获取根目录/tmp_root_path节点的子目录节点列...");System.out.println(zk.getChildren("/tmp_root_path", true));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("...");// 创建第二个子目录节点// 路径为/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/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数据...");zk.setData("/tmp_root_path","我是修改数据后的根目录/tmp_root_path".getBytes(), -1);System.out.println("修改根目录节点/tmp_root_path数据成功!");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();}}}}}
        执行结果如下:

............开始连接ZooKeeper...ZooKeeper连接创建成功!已经触发了None事件!............开始创建根目录节点/tmp_root_path...根目录节点/tmp_root_path创建成功!............开始获取根目录/tmp_root_path节点的子目录节点列...[]根目录/tmp_root_path节点的子目录节点列获取成功!............开始创建第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1创建成功!已经触发了NodeChildrenChanged事件!............开始创建第二个子目录节点/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数据成功!............开始删除第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1删除成功!............开始删除第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2删除成功!............开始删除根目录节点/tmp_root_path...根目录节点/tmp_root_path删除成功!............释放ZooKeeper连接成功!
        而当我们在获取子目录节点列表getChildren()方法调用之后,接着调用修改根目录节点数据的setData()方法,添加代码和结果如下:

// 修改根目录节点数据System.out.println("开始修改根目录节点/tmp_root_path数据...");zk.setData("/tmp_root_path","我是修改数据后的根目录/tmp_root_path".getBytes(), -1);System.out.println("修改根目录节点/tmp_root_path数据成功!");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节点的子目录节点列...[]根目录/tmp_root_path节点的子目录节点列获取成功!............开始修改根目录节点/tmp_root_path数据...修改根目录节点/tmp_root_path数据成功!............开始创建第一个子目录节点/tmp_root_path/childPath1...已经触发了NodeChildrenChanged事件!第一个子目录节点/tmp_root_path/childPath1创建成功!............开始创建第二个子目录节点/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数据成功!............开始删除第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1删除成功!............开始删除第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2删除成功!............开始删除根目录节点/tmp_root_path...根目录节点/tmp_root_path删除成功!............释放ZooKeeper连接成功!
        它仍然只是监控根目录下的子节点变化情况,而且触发的是NodeChildrenChanged事件!而当我们在创建第一个子节点后如果再创建它的一个子节点,并且在创建之前还是先获取根目录/tmp_root_path节点的子目录节点列,执行结果会怎么样呢?添加的代码和执行结果如下:

// 获取子目录节点列表System.out.println("开始获取根目录/tmp_root_path节点的子目录节点列...");System.out.println(zk.getChildren("/tmp_root_path", true));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/childPath1// 节点内容为字符串"我是第一个子目录/tmp_root_path/childPath1/childPath1"// 创建模式为CreateMode.PERSISTENTSystem.out.println("开始创建第一个子目录节点的子节点/tmp_root_path/childPath1/childPath1...");zk.create("/tmp_root_path/childPath1/childPath1","我是第一个子目录的子节点/tmp_root_path/childPath1/childPath1".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);System.out.println("第一个子目录节点的子节点/tmp_root_path/childPath1/childPath1创建成功!");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节点的子目录节点列...[]根目录/tmp_root_path节点的子目录节点列获取成功!............开始修改根目录节点/tmp_root_path数据...修改根目录节点/tmp_root_path数据成功!............开始创建第一个子目录节点/tmp_root_path/childPath1...第一个子目录节点/tmp_root_path/childPath1创建成功!已经触发了NodeChildrenChanged事件!............开始获取根目录/tmp_root_path节点的子目录节点列...[childPath1]根目录/tmp_root_path节点的子目录节点列获取成功!............开始创建第一个子目录节点的子节点/tmp_root_path/childPath1/childPath1...第一个子目录节点的子节点/tmp_root_path/childPath1/childPath1创建成功!............开始创建第二个子目录节点/tmp_root_path/childPath2...已经触发了NodeChildrenChanged事件!第二个子目录节点/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数据成功!............开始删除第一个子目录节点/tmp_root_path/childPath1...org.apache.zookeeper.KeeperException$NotEmptyException: KeeperErrorCode = Directory not empty for /tmp_root_path/childPath1at org.apache.zookeeper.KeeperException.create(KeeperException.java:125)at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)at org.apache.zookeeper.ZooKeeper.delete(ZooKeeper.java:873)at com.jngreen.bgm.scheduler.TestZooKeeperWatcher.main(TestZooKeeperWatcher.java:197)释放ZooKeeper连接成功!
        还是只会监控直接子目录下的节点,在增加第二个节点时触发NodeChildrenChanged事件,并不会越级监控!当然,出现org.apache.zookeeper.KeeperException$NotEmptyException异常是因为我们删除第一个节点时,由于其还有节点,所以才会报错!

        还有一件有意思的事情,当我们在修改第一个子节点数据前获取根目录/tmp_root_path节点的子目录节点列表,调用getChildren()方法,结果会怎样呢?添加处的代码和执行结果如下:

// 获取子目录节点列表System.out.println("开始获取根目录/tmp_root_path节点的子目录节点列...");System.out.println(zk.getChildren("/tmp_root_path", true));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数据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("...");
............开始连接ZooKeeper...ZooKeeper连接创建成功!已经触发了None事件!............开始创建根目录节点/tmp_root_path...根目录节点/tmp_root_path创建成功!............开始获取根目录/tmp_root_path节点的子目录节点列...[]根目录/tmp_root_path节点的子目录节点列获取成功!............开始修改根目录节点/tmp_root_path数据...修改根目录节点/tmp_root_path数据成功!............开始创建第一个子目录节点/tmp_root_path/childPath1...已经触发了NodeChildrenChanged事件!第一个子目录节点/tmp_root_path/childPath1创建成功!............开始创建第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2创建成功!............开始获取根目录/tmp_root_path节点的子目录节点列...[childPath2, childPath1]根目录/tmp_root_path节点的子目录节点列获取成功!............开始修改第一个子目录节点/tmp_root_path/childPath1数据...修改第一个子目录节点/tmp_root_path/childPath1数据成功!............开始修改第二个子目录节点/tmp_root_path/childPath2数据...修改第二个子目录节点/tmp_root_path/childPath2数据成功!............开始修改根目录节点/tmp_root_path数据...修改根目录节点/tmp_root_path数据成功!............开始删除第一个子目录节点/tmp_root_path/childPath1...已经触发了NodeChildrenChanged事件!第一个子目录节点/tmp_root_path/childPath1删除成功!............开始删除第二个子目录节点/tmp_root_path/childPath2...第二个子目录节点/tmp_root_path/childPath2删除成功!............开始删除根目录节点/tmp_root_path...根目录节点/tmp_root_path删除成功!............释放ZooKeeper连接成功!
        也是只监控一次,但是,但是,但是,它只监控根目录子节点的增减情况,至于数据是否发生变化,完全不会监控!这也正是为什么修改第一个子节点数据没有触发,而删除第一个子节点时会触发NodeChildrenChanged事件的原因!


        结论:

         getChildren()方法仅仅监控对应节点直接子目录的一次变化,但是只会监控直接子节点的增减情况,不会监控数据变化情况!若要每次对应节点发生增减变化都被监测到,那么每次都得先调用getChildren()方法获取一遍节点的子节点列表!










3 0
原创粉丝点击