ZK源码解析之Watcher机制

相关类

Watcher 接口

任何一个事件处理类都必须实现Watcher 接口,它有一个内部接口 Event,以及 process方法。前者定义了ZK的状态事件类型的枚举,后者则定义了事件的回调方法

@InterfaceAudience.Public
public interface Watcher {
   
    @InterfaceAudience.Public
    public interface Event {
   
        @InterfaceAudience.Public
        public enum KeeperState {
   /*...*/}
        
        @InterfaceAudience.Public
        public enum EventType {
   /*...*/}
    }
    
    abstract public void process(WatchedEvent event);
}

回调方法 process只有一个参数 WatchedEvent,这个类也很简单,只有三个参数,分别是通知状态、事件类型,以及节点路径。

public class WatchedEvent {
   
    final private KeeperState keeperState;
    final private EventType eventType;
    private String path;
    /*...*/
}

WatchedEvent 紧密相关的还有 WatcherEvent,两者都是对ZK服务端事件的封装,不过后者实现了序列化接口,可用于网络传输。
ZK服务端会将 WatchedEvent 包装成 WatcherEvent进行传输,客户端则需逆向处理,解包装成WatchedEvent来处理事件。

可以看到,WatchedEventWatcherEvent 都只有简单的事件本身的信息,而不包含具体的内容,因此需要客户端主动去获取感兴趣的最新数据。


工作机制

客户端注册

客户端可以通过 getData()getChildren()exist()三个接口来向服务端注册 Watcher。注册的原理都是相同的,这里仅以 getData() 为例进行分析。

getData 有两个重载方法,区别在于第二个参数。

// 使用自定义的 watcher
public byte[] getData(final String path, Watcher watcher, Stat stat)
// 是否使用默认的 watcher
public byte[] getData(String path, boolean watch, Stat stat)

默认的 watcher 在实例化 ZooKeeper 的时候指定:

public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)

ZooKeeper 实例维护了一个 ZKWatchManager 类的实例,该类实现了ClientWatchManager接口,是客户端的 watcher 管理器。
默认 watcher 就保存在 ZKWatchManagerdefaultWatcher 中。

private final ZKWatchManager watchManager = new ZKWatchManager();

private static class ZKWatchManager implements ClientWatchManager {
   
    private final Map<String, Set<Watcher>> dataWatches =
        new HashMap<String, Set<Watcher>>();
    private final Map<String, Set<Watcher>> existWatches =
        new HashMap<String, Set<Watcher>>();
    private final Map<String, Set<Watcher>> childWatches =
        new HashMap<String, Set<Watcher>>();

    private volatile Watcher defaultWatcher;
    /* ... */
}

回到getData,传递 watcher 参数后,首先会被封装成 WatchRegistration 对象,并设置 request 对象为“使用watcher监听”:

public byte[] getData(final String path, Watcher watcher, Stat stat)
    throws KeeperException, InterruptedException {
   
    /* ... */
    WatchRegistration wcb = null;
    if (watcher != null) {
   
        wcb = new DataWatchRegistration(watcher, clientPath);
    }
    /* ... */
    request.setWatch(watcher != null);
    ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);
    /* ... */
}

然后在客户端连接对象cnxn(ClientCnxn)的 submitR

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值