Watcher的用途
一、用于监听节点数据产生的变化,在zk中可以配置集群的通用配置,当配置数据发生了变化之后通知所有订阅该节点的Watcher,该节点发生事件类型
二、用于监听节点状态的变化,比如创建一个节点、删除一个节点等对节点的操作
三、管理客户端与服务端连接的生命周期
Zookeeper中的监听主要时针对于对节点的监听,当有一个客户端连接上zk服务器,虽然在zk中会产生以一个sessionId来表征这个客户端,但是如果该客户端没有对zk的任何节点产生操作,那么该客户的行为不会被其他的客户端所感知。当客户在执行create / delete /set 节点操作后,zk回调监听者client,通知节点所发生的变化。
Watcher的实现流程
zk中存在有三种不同的监听器,分别是getData()监听节点的数据变化,checkExists()检测节点是否还存在,getChildren()监听子节点的状态变化。当客户端对某一种行为进行监听时,如果节点发生了变化,服务器会通过RPC调用Watcher接口的process()方法通知客户端,接口会返回一个WatchedEvent信息类,在WatchedEvent中包含有KeeperState节点状态、EventType事件类型以及path节点路径信息。
Zookeeper原生Watcher的代码实现
- 建立连接时,创建监听器
public class Connect implements Watcher {
// 通过CountDownLatch保证建立连接之后,才能进行节点操作
private CountDownLatch latch = new CountDownLatch(1);
public ZooKeeper connect() throws IOException {
return new ZooKeeper("182.182.182.182:2181",1000,this);
}
// 默认的监听器处理逻辑
@Override
public void process(WatchedEvent watchedEvent) {
// 对节点状态的监听
Event.KeeperState state = watchedEvent.getState();
// 对事件类型的监听
Event.EventType type = watchedEvent.getType();
switch (state) {
case Unknown:
break;
case Disconnected:
break;
case NoSyncConnected:
break;
case SyncConnected:
// 等待client与服务端连接建立完毕
latch.countdown();
break;
case AuthFailed:
break;
case ConnectedReadOnly:
break;
case SaslAuthenticated:
break;
case Expired:
break;
case Closed:
break;
}
System.out.println(state + "================="+type);
}
}
ZooKeeper的构造方法中传入的watcher将会作为整个zk会话期间的默认watcher,该watcher会一直保存为客户端ZKWatchManager的defaultWatcher成员,如果有其他的设置,这个watcher会被覆盖。
Tips:通过Zookeeper客户端来操作节点时,需要确保客户端与服务端已经建立连接。在写demo的过程中公子我也由于没有注意到建立连接是一个异步操作,马上开始创建节点,从而导致创建节点失败。
- 节点操作的过程中建立的监听器
在对本节点进行新增、修改、删除操作时,可以对节点的操作绑定监听
public void addNode(String path, String data) throws KeeperException, InterruptedException {
// 新建节点之后的监听器
zkConn.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, new AsyncCallback.StringCallback() {
@Override
public void processResult(int i, String s, Object o, String s1) {
System.out.println(s + s1);
}
},"addNode");
}
public void deleteNode(String path) throws KeeperException, InterruptedException {
// 删除节点的监听器
zkConn.delete(path, 1, new AsyncCallback.VoidCallback() {
@Override
public void processResult(int i, String s, Object o) {
System.out.println(i + "========" + s + "----------------" + o);
}
},"delete");
}
public void updateNode(String path,String data){
zkConn.setData(path, data.getBytes(), 1, new AsyncCallback.StatCallback() {
// 更新节点之后的监听器
@Override
public void processResult(int i, String s, Object o, Stat stat) {
System.out.println(s);
}
}, "hello");
}