在 ZooKeeper 类中,我们可以通过 getChildren 方法获取指定节点的子节点列表。
List<String> getChildren(String path, boolean watch) 返回给定路径节点的子节点列表。如果 watch 为 true 且调用成功(无异常抛出),则会监听给定路径节点。如果删除给定路径的节点或在该节点下创建/删除子节点的操作成功,则会触发监视。返回的子节点列表不排序,也不保证其自然顺序或词法顺序。如果不存在具有给定路径的节点,将抛出错误代码为 KeeperException.NoNode 的 KeeperException。
void getChildren(String path, boolean watch, AsyncCallback.Children2Callback cb, Object ctx) 方法异步版本。
void getChildren(String path, boolean watch, AsyncCallback.ChildrenCallback cb, Object ctx) 方法异步版本。
List<String> getChildren(String path, boolean watch, Stat stat) 返回给定 znode 路径的状态和子节点列表。
List<String> getChildren(String path, Watcher watcher) 返回给定路径节点的子节点列表。
void getChildren(String path, Watcher watcher, AsyncCallback.Children2Callback cb, Object ctx) 异步版本。
void getChildren(String path, Watcher watcher, AsyncCallback.ChildrenCallback cb, Object ctx) 异步版本。
List<String> getChildren(String path, Watcher watcher, Stat stat) 返回给定 znode 路径的状态和子节点列表。
参数说明:
path - 节点路径
watch - 是否给节点添加监听,如果设置为 true,则修改/删除节点时将会触发节点上注册的监听器
cb - 回调接口
ctx - 上下文对象,用于向回调接口传递扩展数据
stat - 状态对象,获取对象数据后,会将节点状态设置到该对象中
watcher - 监听器,直接给节点注册监听器
该示例演示如何通过 ZooKeeper 类的 getChildren 方法获取指定节点的子节点列表,代码如下:
package com.hxstrive.zookeeper;
import com.alibaba.fastjson.JSONObject;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
* 获取节点子节点列表
* @author hxstrive.com
*/
public class GetChildrenNode {
private static ZooKeeper zooKeeper;
@Before
public void init() throws Exception {
zooKeeper = new ZooKeeper("127.0.0.1:2181", 2000, new Watcher() {
public void process(WatchedEvent watchedEvent) {
System.out.println("触发了 " + watchedEvent.getType() + " 事件");
}
});
// 如果节点不存在,则创建节点,初始化数据
createNode("/getChildren_node", "getChildren节点数据");
createNode("/getChildren_node/books", "书籍列表");
createNode("/getChildren_node/books/java", "《Java编程》");
createNode("/getChildren_node/books/c#", "《C#编程》");
createNode("/getChildren_node/books/c++", "《C++编程》");
createNode("/getChildren_node/jobs", "工作集合");
createNode("/getChildren_node/jobs/chef", "厨师");
createNode("/getChildren_node/jobs/teacher", "教师");
}
private void createNode(String path, String data) throws Exception {
Stat stat = zooKeeper.exists(path, false);
if(null == stat) {
// 节点不存在,创建该节点
String nodeName = zooKeeper.create(path, data.getBytes(),
ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("成功创建 " + nodeName + " 节点");
}
}
/**
* 同步获取节点子节点列表
*/
@Test
public void syncDemo() throws Exception {
// 注册监听器
zooKeeper.register(new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("监听器 " + JSONObject.toJSONString(watchedEvent));
}
});
// 获取 /getChildren_node 节点的子节点列表,且监听该节点
// 注意:这里只会获取到 /getChildren_node 节点的直接子节点,不会获取子节点的子节点
List<String> nodeList = zooKeeper.getChildren("/getChildren_node", true);
System.out.println("子节点:" + Arrays.toString(nodeList.toArray()));
// 创建一个子节点触发监听器
createNode("/getChildren_node/tmp", "temp");
Thread.sleep(1000);
//输出:
//触发了 None 事件
//成功创建 /getChildren_node/books 节点
//...
//子节点:[books, jobs]
//成功创建 /getChildren_node/tmp 节点
//监听器 {"path":"/getChildren_node","state":"SyncConnected","type":"NodeChildrenChanged",
// "wrapper":{"path":"/getChildren_node","state":3,"type":4}}
}
@Test
public void syncDemo2() throws Exception {
// 获取 /getChildren_node 节点的子节点列表,且监听该节点
// 注意:这里只会获取到 /getChildren_node 节点的直接子节点,不会获取子节点的子节点
List<String> nodeList = zooKeeper.getChildren("/getChildren_node", new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("监听器 " + JSONObject.toJSONString(watchedEvent));
}
});
System.out.println("子节点:" + Arrays.toString(nodeList.toArray()));
// 创建一个子节点触发监听器
createNode("/getChildren_node/tmp", "temp");
Thread.sleep(1000);
//输出:
//触发了 None 事件
//子节点:[books, jobs]
//成功创建 /getChildren_node/tmp 节点
//监听器 {"path":"/getChildren_node","state":"SyncConnected","type":"NodeChildrenChanged",
// "wrapper":{"path":"/getChildren_node","state":3,"type":4}}
}
/**
* 异步获取节点子节点列表
*/
@Test
public void asyncDemo() throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(2);
// 获 /getChildren_node 节点的取子节点列表
// 采用 AsyncCallback.Children2Callback 回调接口,processResult 方法多了一个 stat 节点状态
zooKeeper.getChildren("/getChildren_node", false, new AsyncCallback.Children2Callback() {
@Override
public void processResult(int i, String s, Object o, List<String> list, Stat stat) {
System.out.println("Children2Callback.i = " + i);
System.out.println("Children2Callback.s = " + s);
System.out.println("Children2Callback.list = " + Arrays.toString(list.toArray()));
System.out.println("Children2Callback.stat = " + JSONObject.toJSONString(stat));
countDownLatch.countDown();
}
}, "扩展数据1");
// 采用 AsyncCallback.ChildrenCallback 回调接口
zooKeeper.getChildren("/getChildren_node", false, new AsyncCallback.ChildrenCallback() {
@Override
public void processResult(int i, String s, Object o, List<String> list) {
System.out.println("ChildrenCallback.i = " + i);
System.out.println("ChildrenCallback.s = " + s);
System.out.println("ChildrenCallback.list = " + Arrays.toString(list.toArray()));
countDownLatch.countDown();
}
}, "扩展数据2");
countDownLatch.await();
//输出:
//触发了 None 事件
//Children2Callback.i = 0
//Children2Callback.s = /getChildren_node
//Children2Callback.list = [books, tmp, jobs]
//Children2Callback.stat = {"aversion":0,"ctime":1704011838603,"cversion":7,"czxid":249,"dataLength":8,
// "ephemeralOwner":0,"mtime":1704011838718,"mzxid":257,"numChildren":3,"pzxid":287,"version":1}
//ChildrenCallback.i = 0
//ChildrenCallback.s = /getChildren_node
//ChildrenCallback.list = [books, tmp, jobs]
}
}