ZK编程-创建节点+watcher(转载)

ZooKeeper编程

CreateMode

PERSISTENT:创建后只要不删就永久存在

EPHEMERAL:会话结束年结点自动被删除

SEQUENTIAL:节点名末尾会自动追加一个10位数的单调递增的序号

PERSISTENT_SEQUENTIAL:结合PERSISTENT和SEQUENTIAL

EPHEMERAL_SEQUENTIAL:结合EPHEMERAL和SEQUENTIAL

复制代码
package basic;

import java.io.IOException;
import java.util.List;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;

public class Demo {
    private static final int TIMEOUT = 3000;

    public static void main(String[] args) throws IOException {
        ZooKeeper zkp = new ZooKeeper("localhost:2181", TIMEOUT, null);
        try {
            // 创建一个EPHEMERAL类型的节点,会话关闭后它会自动被删除
            zkp.create("/node1", "data1".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);
            if (zkp.exists("/node1", false) != null) {
                System.out.println("node1 exists now.");
            }
            try {
                // 当节点名已存在时再去创建它会抛出KeeperException(即使本次的ACL、CreateMode和上次的不一样)
                zkp.create("/node1", "data1".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
            } catch (KeeperException e) {
                System.out.println("KeeperException caught:" + e.getMessage());
            }

            // 关闭会话
            zkp.close();
            
            zkp = new ZooKeeper("localhost:2181", TIMEOUT, null);
            //重新建立会话后node1已经不存在了
            if (zkp.exists("/node1", false) == null) {
                System.out.println("node1 dosn't exists now.");
            }
            //创建SEQUENTIAL节点
            zkp.create("/node-", "same data".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT_SEQUENTIAL);
            zkp.create("/node-", "same data".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT_SEQUENTIAL);
            zkp.create("/node-", "same data".getBytes(), Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT_SEQUENTIAL);
            List children = zkp.getChildren("/", null);
            System.out.println("Children of root node:");
            for (String child : children) {
                System.out.println(child);
            }

            zkp.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
复制代码

第一次运行输出:

node1 exists now.
KeeperException caught:KeeperErrorCode = NodeExists for /node1
node1 dosn't exists now.
Children of root node:
node-0000000003
zookeeper
node-0000000002
node-0000000001

第二次运行输出:

node1 exists now.
KeeperException caught:KeeperErrorCode = NodeExists for /node1
node1 dosn't exists now.
Children of root node:
node-0000000003
zookeeper
node-0000000002
node-0000000001
node-0000000007
node-0000000005
node-0000000006

注意两次会话中创建的PERSISTENT_SEQUENTIAL节点序号并不是连续的,比如上例中缺少了node-0000000004.

Watcher & Version

WatchEvent有两种类型:NodeDataChanged、NodeDeleted和NodeChildrenChanged。

调用setData()时会触发NodeDataChanged;

调用delete()时上述三种event都会触发。

要exists()中安放的Watcher监听NodeDataChanged、NodeDeleted型Event;

要getData()中安放的Watcher监听NodeDataChanged、NodeDeleted型Event;(如果这种event都被触发,比如发生了delete,那getData是收到NodeDataChanged呢还是收到NodeDeleted呢?)

要getChildren()中安放的Watcher监听NodeChildrenChanged型Event.

方法一:

复制代码
package basic;
import java.io.IOException;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;

public class Demo {
    private static final int TIMEOUT=3000;
    
    private static Watcher getWatcher(final String msg){
        return new Watcher(){
            @Override
            public void process(WatchedEvent event) {
                System.out.println(msg+"\t"+event.getType().name());
            }
        };
    }

    public static void main(String[] args) throws IOException{
        //建立连接,触发Watcher
        ZooKeeper zkp=new ZooKeeper("localhost:2181",TIMEOUT,getWatcher("Connection changed"));
        try{
            zkp.create("/node1", "data1".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            zkp.exists("/node1", getWatcher("Existence changed"));
            Stat stat=new Stat();
            //getData时获取version,因为在setData和delete时需要提供正确的version
            byte[] data=zkp.getData("/node1", getWatcher("Nodedata changed"), stat);
            System.out.println("NodeData is:"+ new String(data));
            zkp.getChildren("/", getWatcher("Children changed"));
            //setData触发exists、getData中的Watcher。setData时会改为version,所以注意要获取新的version
            stat=zkp.setData("/node1","newdata".getBytes(), stat.getVersion());
            //delete触发exists、getData、getChildren中的Watcher
            zkp.delete("/node1", stat.getVersion());
            zkp.close();
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
}
复制代码

运行输出:

Connection changed None
NodeData is:data1
Existence changed NodeDataChanged
Nodedata changed NodeDataChanged
Children changed NodeChildrenChanged

调用delete时会触发NodeDeleted,但是在上例中exists并没有监听到该事件,这正验证了Watcher是一次性的,因为在delete之前调用了setData,exists监听到NodeDataChanged事件后,它上面的Watcher就失效了。

把CreateMode改为EPHEMERAL后,即使没有显式调用setData()和delete(),运行输出也跟上面一样,因为在close()时隐式调用了delete()。

复制代码
zkp.create("/node1", "data1".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
zkp.exists("/node1", getWatcher("Existence changed"));
Stat stat=new Stat();
byte[] data=zkp.getData("/node1", getWatcher("Nodedata changed"), stat);
System.out.println("NodeData is:"+ new String(data));
zkp.getChildren("/", getWatcher("Children changed"));
zkp.close();
复制代码

方法二:

上面是分别给exists、getData、getChildren等安装不同的Watcher。也可以整个Session上安装一个统一的Watcher,然后在调用exists、getData、getChildren时用true或false来指定要不要安装Watcher。

复制代码
package basic;
import java.io.IOException;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;

public class Demo3 {
    private static final int TIMEOUT=3000;
    
    private static Watcher getWatcher(){
        return new Watcher(){
            @Override
            public void process(WatchedEvent event) {
                System.out.println(event.toString());
            }
        };
    }

    public static void main(String[] args) throws IOException{
        ZooKeeper zkp=new ZooKeeper("localhost:2181",TIMEOUT,null);
        try{
            //一次性注意Watcher
            zkp.register(getWatcher());
            zkp.create("/node1", "data1".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            Stat stat=new Stat();
            byte[] data=zkp.getData("/node1", false, stat);
            zkp.exists("/node1", false);
            zkp.getChildren("/", false);
            System.out.println("NodeData is:"+ new String(data));
            stat=zkp.setData("/node1", "newdata".getBytes(), stat.getVersion());
            zkp.delete("/node1", stat.getVersion());
            zkp.close();
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
}
复制代码

运行输出:

WatchedEvent state:SyncConnected type:None path:null
NodeData is:data1

我们看到调用exists、getData、getChildren时都设为false,Watcher仍然被调用了一次。

改为

byte[] data=zkp.getData("/node1", true, stat);
zkp.exists("/node1", false);
zkp.getChildren("/", false);

输出:

WatchedEvent state:SyncConnected type:None path:null
NodeData is:data1
WatchedEvent state:SyncConnected type:NodeDataChanged path:/node1

改为

byte[] data=zkp.getData("/node1", false, stat);
zkp.exists("/node1", true);
zkp.getChildren("/", false);

输出:

WatchedEvent state:SyncConnected type:None path:null
NodeData is:data1
WatchedEvent state:SyncConnected type:NodeDataChanged path:/node1

改为

byte[] data=zkp.getData("/node1", false, stat);
zkp.exists("/node1", false);
zkp.getChildren("/", true);

输出:

WatchedEvent state:SyncConnected type:None path:null
NodeData is:data1
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/

改为

byte[] data=zkp.getData("/node1", true, stat);
zkp.exists("/node1", true);
zkp.getChildren("/", false);
System.out.println("NodeData is:"+ new String(data));
//stat=zkp.setData("/node1", "newdata".getBytes(), stat.getVersion());
zkp.delete("/node1", stat.getVersion());

输出:

WatchedEvent state:SyncConnected type:None path:null
NodeData is:data1
WatchedEvent state:SyncConnected type:NodeDeleted path:/node1
注意本次getData和exists收到的EventType都是NodeDeleted,而Watcher是在Session上注册的,所以Watcher只被调用了一次。有一点不解的是:为什么这次调用delete,getData收到的是NodeDeleted,而在方法一中收到的是NodeDataChanged?

改为

byte[] data=zkp.getData("/node1", true, stat);
zkp.exists("/node1", true);
zkp.getChildren("/", true);
System.out.println("NodeData is:"+ new String(data));
//stat=zkp.setData("/node1", "newdata".getBytes(), stat.getVersion());
zkp.delete("/node1", stat.getVersion());

输出:

WatchedEvent state:SyncConnected type:None path:null
NodeData is:data1
WatchedEvent state:SyncConnected type:NodeDeleted path:/node1
WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/

ACL

原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun

你可能感兴趣的:(ZooKeeper)