zookeeper的监听器原理

本文详细介绍了ZooKeeper的监听原理,包括客户端如何注册监听、ZooKeeper如何通知客户端以及常见的监听类型。通过实例展示了节点数据变化和子节点增减的监听,并提供了Java API的使用示例,解释了监听器触发的四种情况以及如何实现持久化监听。
摘要由CSDN通过智能技术生成

        客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、节点删除、子目 录节点增加删除)时,ZooKeeper 会通知客户端。监听机制保证 ZooKeeper 保存的任何的数据的任何改变都能快速的响应到监听了该节点的应用程序。

        zookeeper只负责通知,具体做不做还要看客户端

1、监听原理详解

(1)首先要有一个main()线程

(2)在main线程中创建Zookeeper客户端,这时就会创建两个线程,一个负责网络连接通信(connet),一个负责监听(listener) 。

(3)通过connect线程将注册的监听事件发送给Zookeeper。

(4)在Zookeeper的注册监听器列表中将注册的监听事件添加到列表中。

(5)Zookeeper监听到有数据或路径变化,就会将这个消息发送给listener线程。

(6) listener线程内部调用了process()方法。

2、常见的监听

(1)监听节点数据的变化

get path [ watch]

(2)监听子节点增减的变化

ls path [watch]

一、节点的值变化监听

1)在 node1 主机上注册监听/client1节点数据变化

[zk: localhost:2181(CONNECTED) 26] get -w /client1

2)在node2主机上修改/client1节点的数据

[zk: localhost:2181(CONNECTED) 1] set /client1 "xisi"

3)观察 node1主机收到数据变化的监听

WATCHER:

WatchedEvent state:SyncConnected

type:NodeDataChanged

path:/client1

注意:在node2再多次修改/client1的值,node上不会再收到监听。因为注册一次,只能监听一次。想再次监听,需要再次注册。

二、节点的子节点变化监听(路径变化)

1)在 node1主机上注册监听/client1节点的子节点变化

[zk: localhost:2181(CONNECTED) 1] ls -w /client1

[yg, tt]

2)在 node2 主机/client2 节点上创建子节点

[zk: localhost:2181(CONNECTED) 2] create /client1/shizi "shizi"

Created /client1/shizi

3)观察 node1 主机收到子节点变化的监听

WATCHER::

WatchedEvent state:SyncConnected type:NodeChildrenChanged

path:/client1

注意:节点的路径变化,也是注册一次,生效一次。想多次生效,就需要多次注册。

 3、zookeeper的监听器的JAVA API

        zookeeper中存储的节点以及节点信息都可以被客户端监听,一旦客户端监听的自己感兴趣的事情产生,那么zookeeper就会通知客户端去做出一些反应。

连接zookeeper一共有三个参数:
        1、String connectStr :zookeeper的地址
        2、sessionTimeout:连接超时时长
        3、watcher:zookeeper的监听器

监听器触发有如下几种情况
        1、通过客户端去查询或者创建、修改zookeeper上的节点都会去触发一次监听器
        2、再去查询zookeeper的节点数据、子节点、节点存在与否的时候也会注册监听器,那么此时这个监听器也可以让他们三个取用

public class ZookeeperWatcherTest {
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        /**
         *
         *关心的监听器有四个地方可以触发:
         *    1、构建zookeeper对象之后 调用zookeeper的方法时候监听器会被触发---不常用
         *    2、getData()---获取节点数据的  里面注册监听器
         *         被触发--当节点的数据发生变化的时候
         *    3、getChildren()----获取节点的子节点信息
         *         被触发---当前节点的子节点列表发生变化会触发
         *    4、exists() ----判断节点存不存在
         *         被触发---当节点被创建或者删除会触发
         *                 或者当节点的数据变化也会去触发
         */
        ZooKeeper zkClient = new ZooKeeper("node1:2181,node2:2181,node3:2181", 2000, new Watcher() {
//Zookeeper()方法中第一个值代表着zookeeper的地址,第二个值代表zookeeper连接超时时间,最后一个是监听器
            @Override
            public void process(WatchedEvent event) {
                System.out.println("zkClient的监听器被触发了");
            }
        });
//        byte[] data = zkClient.getData("/java", true, new Stat());//true代表使用zookeeper监听器
        byte[] data = zkClient.getData("/java", new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                System.out.println("getData自定义的监听器被触发了");
            }
        }, new Stat());
        System.out.println(new String(data));
        Thread.sleep(Long.MAX_VALUE);
    }
}

监听器有四个地方可以触发:
        1、构建zookeeper对象之后 调用zookeeper的方法时候监听器会被触发---不常用
        2、getData()---获取节点数据的  里面注册监听器
                被触发--当节点的数据发生变化的时候
         3、getChildren()----获取节点的子节点信息
                被触发---当前节点的子节点列表发生变化会触发
         4、exists() ----判断节点存不存在
                被触发---当节点被创建或者删除会触发
                或者当节点的数据变化也会去触发

如何做到持久化监听呢?

public class MoreTimesWatcher {
    static  ZooKeeper zkClient;
    public static void main(String[] args) throws Exception {
        zkClient= new ZooKeeper("node1:2181,node2:2181,node3:2181", 2000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                /**
                 * 如果想持久监听 我们需要再监听器被触发之后再次去注册一下这个监听器即可
                 */
                try {
                    byte[]  data = zkClient.getData("/java", true, new Stat());
                    System.out.println(new String(data));
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });
        byte[] data = zkClient.getData("/java", true, new Stat());//监听一次以后再去执行process()方法重新调用此监听器进行监听
        System.out.println(new String(data));
        Thread.sleep(Long.MAX_VALUE);
    }
}

接下来我们看一下子节点列表监听的java代码:

/**
 * 监听子节点列表的变化
 */
public class NodeListWatcher {
    static ZooKeeper zkClient;
    public static void main(String[] args) throws Exception {
        zkClient= new ZooKeeper("node1:2181,node2:2181,node3:2181", 2000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                try {
                    List<String> children = zkClient.getChildren("/java", true);
                    System.out.println(children);
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        List<String> children = zkClient.getChildren("/java", true);
        System.out.println(children);
        Thread.sleep(Long.MAX_VALUE);
    }
}

判断节点是否存在:

/**
 * 判断节点是否存在的一个监听器:
 *    两种情况:
 *      1、节点创建或删除
 *      2、节点数据发生变化也会触发
 */
public class ExistsWatcher {
    static ZooKeeper zkClient;
    public static void main(String[] args) throws Exception {
        zkClient= new ZooKeeper("node1:2181,node2:2181,node3:2181", 2000, new Watcher() {
            @Override
            public void process(WatchedEvent event) {
                try {
                    Stat stat  = zkClient.exists("/java", true);
                    System.out.println(stat==null?"节点不存在":"节点存在");
                } catch (KeeperException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Stat stat = zkClient.exists("/java", true);
        System.out.println(stat==null?"节点不存在":"节点存在");
        Thread.sleep(Long.MAX_VALUE);
    }
}

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值