Zookeeper Java API (三) zk节点的通知(Watcher)和回调(CallBack)

Zk中的通知(Watcher)

ZooKeeper中实现对接点的监控,需要实现Watcher接口类,实现其中的process方法

public class WatcherDemo implements Watcher{
    public void process(WatchedEvent event) {

    }
}

WatcherEvent对如下状态进行监听
1. ZooKeeper会话状态:Disconnected,SyncConnected,AuthFailed,ConnectedReadOnly,SaslAuthenticated和Expired
2. 事件类型:NodeCreated,NodeDeleted,NodeDataChanged,NodeChildrenChanged和None
3. 事件类型不是None时,返回一个znode路径

如何设置一个监视点

对节点的建立设置监视点
/**
 * @author Eason
 * @create 2018-04-07 21:41
 **/
public class WatcherDemo implements Watcher {

    public void process(WatchedEvent event) {
        System.out.println("Enter the process method,the event is :"+event);
        Event.EventType type = event.getType();
        switch (type) {
            case NodeDeleted:
                System.out.println("新建节点:" + event.getPath());
        }
    }

    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        String connectionString = "192.168.1.6:2181,192.168.1.6:2182,192.168.1.6:2183";
        ZooKeeper zooKeeper = new ZooKeeper(connectionString, 15 * 1000, new WatcherDemo(), false);
        zooKeeper.create("/myEphmeralPath1", "random".getBytes(), OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        TimeUnit.SECONDS.sleep(60);
        zooKeeper.close();
    }
}

执行完成后 控制台输出

Connected to the target VM, address: '127.0.0.1:50459', transport: 'socket'
Enter the process method,the event is :WatchedEvent state:SyncConnected type:None path:null
Disconnected from the target VM, address: '127.0.0.1:50459', transport: 'socket'

为什么没有监控到节点的创建呢?

首先,我们在创建ZK连接时指定了一个Watcher,但是这个Watcher指监控到了ZK连接成功的状态SyncConnected.这里同样有一个问题,为什么关闭客户端时没有监控到Disconnected事件呢.对于这个问题,个人理解是因为当前客户端失去连接,Watcher失效,在debug模式下使用同一个Watcher可以监控到Disconnected事件

/**
 * @author Eason
 * @create 2018-04-07 21:41
 **/
public class WatcherDemo implements Watcher {

    public void process(WatchedEvent event) {
        System.out.println("Enter the process method,the event is :"+event);
        Event.EventType type = event.getType();
        switch (type) {
            case NodeDeleted:
                System.out.println("新建节点:" + event.getPath());
        }
    }

    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        String connectionString = "192.168.1.6:2181,192.168.1.6:2182,192.168.1.6:2183";
        ZooKeeper zooKeeper = new ZooKeeper(connectionString, 15 * 1000, new WatcherDemo(), false);
        ZooKeeper zooKeeper1 = new ZooKeeper(connectionString, 15 * 1000, new WatcherDemo(), false);
        zooKeeper.create("/myEphmeralPath1", "random".getBytes(), OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        zooKeeper.close();
        TimeUnit.SECONDS.sleep(60);
    }
}

控制台输出

Enter the process method,the event is :WatchedEvent state:SyncConnected type:None path:null
Enter the process method,the event is :WatchedEvent state:SyncConnected type:None path:null
Enter the process method,the event is :WatchedEvent state:Disconnected type:None path:null
Enter the process method,the event is :WatchedEvent state:Expired type:None path:null

注意的是需要debug模式下才可以看到输出结果,具体原因不清楚.

现在回到第一个问题,如何对创建节点设置监控呢?
首先看一下create有关的API

public String create(final String path, byte data[], List acl, CreateMode createMode)
public void create(final String path, byte data[], List acl,CreateMode createMode,  StringCallback cb, Object ctx)

可以看到,create方法是没有Watcher相关方法的,因此,基于判断没有就创建的思想,可以使用exist API来设置一个监视点

/**
 * @author Eason
 * @create 2018-04-07 21:41
 **/
public class WatcherDemo01 implements Watcher {

    public void process(WatchedEvent event) {
        System.out.println("Enter the process method,the event is :" + event);
        Event.EventType type = event.getType();
        switch (type) {
            case NodeCreated:
                System.out.println("新建节点:" + event.getPath());
            case NodeDeleted:
                System.out.println("删除节点:" + event.getPath());
            case NodeDataChanged:
                System.out.println("修改节点:" + event.getPath());
            case NodeChildrenChanged:
                System.out.println("子节点:" + event);
        }
    }

    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
        WatcherDemo01 watcherDemo = new WatcherDemo01();
        String connectionString = "192.168.1.6:2181,192.168.1.6:2182,192.168.1.6:2183";
        ZooKeeper zooKeeper = new ZooKeeper(connectionString, 15 * 1000, watcherDemo, false);
        String path = "/watcherdemo01";
        String childPath = "/watcherdemo01/child01";

        Stat stat = zooKeeper.exists(path, watcherDemo);
        if (stat == null) {
            zooKeeper.create(path, "random".getBytes(), OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        if (stat != null) {
            zooKeeper.delete(path, stat.getVersion());
        }
        TimeUnit.SECONDS.sleep(5);
        zooKeeper.close();
    }
}

如何设置监控点

下面是对如何设置监控点的总结
- 对于NodeCreated 通过exists API设置
- 对于NodeDeleted 通过exists 和 getData()设置
- 对于NodeDataChanged 通过exists或getData设置
- 对于NodeChildrenChanged 通过getChildren设置

ZooKeeper回调

首先要区分通知和回调的区别,通知是ZooKeeper中注册了监视点的客户端收到的事件报告消息,而回调是基于异步思想的,通过回调函数来确定操作的完成情况

创建节点的回调通知
/**
 * @author Eason
 * @create 2018-04-07 22:47
 **/
public class CallBackDemo implements Watcher {
    public static void main(String[] args) throws InterruptedException, IOException {
        String connectionString = "192.168.1.6:2181,192.168.1.6:2182,192.168.1.6:2183";
        ZooKeeper zooKeeper = new ZooKeeper(connectionString, 15 * 1000, new CallBackDemo(), false);
        String path = "/callBackDemo";
        String params = "123";
        zooKeeper.create(path, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, new AsyncCallback.StringCallback() {
            public void processResult(int rc, String path, Object ctx, String name) {
                System.out.println("Object ctx 参数对应于create 方法最后一个参数");
                System.out.println(ctx.toString());
                KeeperException.Code code = KeeperException.Code.get(rc);
                switch (code) {
                    case OK:
                    case NOAUTH:
                    case NONODE:
                    case APIERROR:
                    case NOTEMPTY:
                    case AUTHFAILED:
                    case BADVERSION:
                    case INVALIDACL:
                    case NODEEXISTS:
                    case NOTREADONLY:
                    case SYSTEMERROR:
                    case BADARGUMENTS:
                    case SESSIONMOVED:
                    case UNIMPLEMENTED:
                    case CONNECTIONLOSS:
                    case SESSIONEXPIRED:
                    case INVALIDCALLBACK:
                    case MARSHALLINGERROR:
                    case OPERATIONTIMEOUT:
                    case DATAINCONSISTENCY:
                    case RUNTIMEINCONSISTENCY:
                    case NOCHILDRENFOREPHEMERALS:
                }
            }
        }, params);
        TimeUnit.SECONDS.sleep(10);
    }

    public void process(WatchedEvent event) {

    }
}

注意Object ctx参数,具体状态吗不再赘述

你可能感兴趣的:(zookeeper)