Zookeeper watcher事件机制源码剖析

一、zk的watcher机制的过程:

1、客户端注册watcher
2、服务端注册watcher
3、服务端触发watcher事件
3、客户端回调watcher
在这里插入图片描述

二、客户端注册watcher有三种方式,可以调用getData,exists、getChildred实现

	public Logger logger = LoggerFactory.getLogger(WatcherDemo.class);
    //zookeeper连接地址
    private static String ZOOKEEPER_PATH = "localhost:2181";
    static ZooKeeper zooKeeper;
    //初始化连接
    static {
   
        try {
   
            //创建一个 ZooKeeper 客户端对象实例时,可以向构造方法中传入一个默认的 Watcher
            zooKeeper = new ZooKeeper(ZOOKEEPER_PATH, 4000, new WatcherDemo());
        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }
    @Override
    public void process(WatchedEvent watchedEvent) {
   
        logger.info("eventType:"+watchedEvent.getType());
        if(watchedEvent.getType() == Event.EventType.NodeDataChanged) {
   
            try {
   
            	//客户端注册watcher
                zooKeeper.exists(watchedEvent.getPath(), true);
            } catch (KeeperException e) {
   
                e.printStackTrace();
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        }
    }
	
	//测试
    public static void main(String[] args) throws KeeperException, InterruptedException, IOException {
   
        //读取配置的文件路径
        String CONF_PATH = "/zookeeper/watch";
        if (zooKeeper.exists(CONF_PATH, false) == null) {
   
            zooKeeper.create(CONF_PATH, "0".getBytes("utf-8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        Thread.sleep(1000);
        System.out.println("-------------");
        Stat stat = zooKeeper.exists(CONF_PATH, true);
        System.in.read();
    }

执行控制台显示:

08:20:25.423 [main-EventThread] INFO com.cxg.common.WatcherDemo - eventType:None

接下来服务端触发事件:

ls /zookeeper/
delete /zookeeper/watch

接下来控制台继续输出:

08:20:26.223 [main-EventThread] INFO com.cxg.common.WatcherDemo - eventType:NodeDeleted

这样就完成了以上的Watcher的基本过程;那么在源码中是怎么实现的呢?

三、就例子中的exists方法来深入剖析watcher原理,getData,getChildred实现基本一致

首先我们要看看watcher的几种事件类型(这里我们可以优雅的利用枚举来实现我们在代码中常用的错误代码):

public enum EventType {
   
      None (-1),
      NodeCreated (1),
      NodeDeleted (2),
      NodeDataChanged (3),
      NodeChildrenChanged (4);

      private final int intValue;     // Integer representation of value
                                      // for sending over wire

      EventType(int intValue) {
   
          this.intValue = intValue;
      }

      public int getIntValue() {
   
          return intValue;
      }

      public static EventType fromInt(int intValue) {
   
          switch(intValue) {
   
              case -1: return EventType.None;
              case  1: return EventType.NodeCreated;
              case  2: return EventType.NodeDeleted;
              case  3: return EventType.NodeDataChanged;
              case  4: return EventType.NodeChildrenChanged;

              default:
                  throw new RuntimeException("Invalid integer value for conversion to EventType");
          }
      }           
  }

四、接下来看看exists究竟干了啥:

  • 检查下路径是否正确
  • 这里将watcher和clientPath捆绑到WatchRegistration对象中备用
  • 设置请求头
  • 设置注册API
  • 封装成request请求
  • 重点中的重点:没有将watcher封装,而是仅仅做了个有没有watcher的标记
  • 然后使用ClientCnxn.submitRequest方法将现存的这些信息进一步封装
public Stat exists(final String path, Watcher watcher)
       throws KeeperException, InterruptedException
   {
   
       final String clientPath = path;
       //检查下路径是否正确
       PathUtils.validatePath(clientPath);

       // the watch contains the un-chroot path
       //重点:这里将watcher和clientPath捆绑到WatchRegistration对象中备用
       WatchRegistration wcb = null;
       if (watcher != null) {
   
           wcb = new ExistsWatchRegistration(watcher, clientPath);
       }

       final String serverPath = prependChroot(clientPath);

	//重点
	//设置请求头
       RequestHeader h = new RequestHeader();
       //设置注册API
       h.setType(ZooDefs
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值