本文总结基于ZooKeeper3.4.10版本。
首先用表格展示写操作(create,set,,delete)与读操作函数(exists,getData,getChiledren)的watch触发关系。
读操作 | create | set | delete | ||||
---|---|---|---|---|---|---|---|
节点 | node | childNode | node | childNode | node | childNode | |
node | exists | NodeCreated | NodeDataChanged | NodeDeleted | |||
node | getData | NodeDataChanged | NodeDeleted | ||||
node | getChildren | NodeChildrenChanged | NodeDeleted | NodeChildrenChanged | |||
childNode | exists | NodeCreated | NodeDataChanged | NodeDeleted | |||
childNode | getData | NodeDataChanged | NodeDeleted | ||||
childNode | getChildren | NodeDeleted |
表详细说明:
假设node = “/test”,childNode = "/test/test1"
- 创建node时,只触发了node的exists函数所设置的Watcher,触发的事件类型为NodeCreated;
- 创建childNode时,触发了childNode的exists函数所设置的Watcher,触发的事件类型为NodeCreated;同时也触发了node的getChildren函数所设置的Watcher,触发的事件类型为NodeChildenChanged;
- 修改node时,只触发了node的exists和getData函数所设置的Watcher,触发的事件类型为NodeDataChanged;
- 修改childNode时,只触发了childNode的exists和getData函数所设置的Watcher,触发的事件类型为NodeDataChanged;
- 删除childNode时,触发了childNode的三个函数所设置的Watcher,触发的事件类型为NodeDeletd;同时也触发了node的getChildren所设置的Watcher,触发的事件类型为NodeDataChanged;
- 删除node时,触发了node的三个函数所设置的Wacher,触发的事件类型为NodeDeleted。
需要注意的几点:
- 删除node时,也会触发node的getChildren函数的Watcher ;
- 删除childNode时,既触发node的getChildren函数又触发childNode的getChildren,只是事件类型不同;
- 只有创建与删除childNode才会node的getChildren函数,修改childNode并不会。
测试代码如下:
public class ZooKeeperUtils {
//创建连接zookeeper的实例
public static ZooKeeper getZKConn(String hosts) throws IOException {
int seesionTimeout = 3000;
System.out.println("zookeeper connecting .....");
ZooKeeper zooKeeper = new ZooKeeper(hosts, seesionTimeout, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("连接事件:" + watchedEvent.getState());
}
});
System.out.println("zookeeper connect success!");
return zooKeeper;
}
//注册Watcher
public static void testWatcher(String host) throws Exception {
String path = "/test";
String pathChild = "/test/test1";
//连接zookeeper
ZooKeeper zooKeeper = getZKConn(host);
//注册“/test”的exists函数的Watcher
Stat stat = zooKeeper.exists(path, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("exists: " + watchedEvent.getType());
}
});
if (stat != null) {
//注册“/test”的getData函数的Watcher
zooKeeper.getData(path, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("getData: " + watchedEvent.getType());
}
}, new Stat());
//注册“/test”的getChildren函数的Watcher
zooKeeper.getChildren(path, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("getChildren: " + watchedEvent.getType());
}
});
}
//注册“/test/test1”的exists函数的Watcher
Stat statChild = zooKeeper.exists(pathChild, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("child exists: " + watchedEvent.getType());
}
});
if(statChild != null){
//注册“/test/test1”的getData函数的Watcher
zooKeeper.getData(pathChild, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("child getData: " + watchedEvent.getType());
}
}, new Stat());
//注册“/test/test1”的getChildren函数的Watcher
zooKeeper.getChildren(pathChild, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("child getChildren: " + watchedEvent.getType());
}
});
}
public static void main(String[] args) throws Exception {
String host = "192.168.56.1:2181"; //zookeeper地址
testWatcher(host);
while (true); //等待触发
}
}
注意:在进行一次写操作之前都需要重新运行一次程序,因为Watcher只能触发一次,所以需要重新运行程序以重新注册Watcher。
参考文章:1. ZooKeeper学习第一期---Zookeeper简单介绍
2. zookeeper(四):核心原理(Watcher、事件和状态)
第一个参考文章写得非常好,可以作为学习材料。