Zookeeper的Api使用

本文详细介绍了Zookeeper的API使用,包括Zookeeper原生API的五个包及其作用,重点讲解了创建会话、创建节点、获取节点数据、修改和删除节点。此外,还对比分析了ZkClient和Curator这两个开源客户端的特性,如ZkClient的递归创建节点功能和Curator的Fluent风格接口,以及两者在创建会话、创建、删除、获取和更新数据上的不同实现。最后提到了Curator的事件监听机制,如NodeCache、PathChildrenCache和TreeCache。
摘要由CSDN通过智能技术生成

Zookeeper api

Zookeeper API共包含五个包,分别为:
(1)org.apache.zookeeper
(2)org.apache.zookeeper.data
(3)org.apache.zookeeper.server
(4)org.apache.zookeeper.server.quorum
(5)org.apache.zookeeper.server.upgrade
其中org.apache.zookeeper,包含Zookeeper类,他是我们编程时最常⽤的类⽂件。这个类是Zookeeper客户端的主要类⽂件。如果要使⽤Zookeeper服务,应⽤程序⾸先必须创建⼀个Zookeeper实例,这时就需要使⽤此类。⼀旦客户端和Zookeeper服务端建⽴起了连接,Zookeeper系统将会给本次连接会话分配⼀个ID值,并且客户端将会周期性的向服务器端发送⼼跳来维持会话连接。只要连接有效,客户端就可以使⽤Zookeeper API来做相应处理了。
准备⼯作:导⼊依赖

<dependency>
	 <groupId>org.apache.zookeeper</groupId>
	 <artifactId>zookeeper</artifactId>
	 <version>3.4.14</version>
 </dependency>

建立会话

public class CreateSession implements Watcher {

    private static final CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws IOException, InterruptedException {
        /*
        客户端可以通过创建一个zk实例来连接zk服务器
        new Zookeeper(connectString,sesssionTimeOut,Wather)
        connectString: 连接地址:IP:端口
        sesssionTimeOut:会话超时时间:单位毫秒
        Wather:监听器(当特定事件触发监听时,zk会通过watcher通知到客户端)
     */
        ZooKeeper zooKeeper = new ZooKeeper("8.129.124.193:2181",5000,new CreateSession());
        System.out.println(zooKeeper.getState());
        countDownLatch.await();
        System.out.println("=========Client Connected to zookeeper==========");
    }


    @Override
    public void process(WatchedEvent watchedEvent) {
        //当连接创建了,服务端发送给客户端SyncConnected事件
        if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
            countDownLatch.countDown();
            System.out.println("连接成功");
        }
    }
}

注意,ZooKeeper 客户端和服务端会话的建⽴是⼀个异步的过程,也就是说在程序中,构造⽅法会在处理完客户端初始化⼯作后⽴即返回,在⼤多数情况下,此时并没有真正建⽴好⼀个可⽤的会话,在会话的⽣命周期中处于“CONNECTING”的状态。 当该会话真正创建完毕后ZooKeeper服务端会向会话对应的客户端发送⼀个事件通知,以告知客户端,客户端只有在获取这个通知之后,才算真正建⽴了会话。

创建节点

public class CreateNote implements Watcher {
    
    private static ZooKeeper zooKeeper = null;

    public static void main(String[] args) throws IOException, InterruptedException {

        zooKeeper = new ZooKeeper("8.129.124.193:2181", 5000, new CreateNote());
      //  countDownLatch.await();
        System.out.println("=========Client Connected to zookeeper==========");
        Thread.sleep(Integer.MAX_VALUE);
    }

    @Override
    public void process(WatchedEvent watchedEvent) {
        //当连接创建了,服务端发送给客户端SyncConnected事件
        if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
        //    countDownLatch.countDown();
            System.out.println("连接成功");
        }

        try {
            createNoteSync();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void createNoteSync() throws Exception {
		/**
		 * path :节点创建的路径
		 * data[] :节点创建要保存的数据,是个byte类型的
		 * acl :节点创建的权限信息(4种类型)
		 * ANYONE_ID_UNSAFE : 表示任何⼈
		 * AUTH_IDS :此ID仅可⽤于设置ACL。它将被客户机验证的ID替
		换。
		 * OPEN_ACL_UNSAFE :这是⼀个完全开放的ACL(常⽤)-->
		world:anyone
		 * CREATOR_ALL_ACL :此ACL授予创建者身份验证ID的所有权限
		 * createMode :创建节点的类型(4种类型)
		 * PERSISTENT:持久节点
		 * PERSISTENT_SEQUENTIAL:持久顺序节点
		 * EPHEMERAL:临时节点
		 * EPHEMERAL_SEQUENTIAL:临时顺序节点
		 String node = zookeeper.create(path,data,acl,createMode);
		 */
        String persistentNode = zooKeeper.create("/jerry", "jerry的持久性节点".getBytes("UTF8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        String persistentSequentialNode = zooKeeper.create("/jerry_sequncetial", "jerry的持久性顺序节点".getBytes("UTF8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
        String ephemeralNode = zooKeeper.create("/jerry_ephemeral", "jerry的临时节点".getBytes("UTF8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        
        System.out.println("创建的持久性节点:" + persistentNode);
        System.out.println("创建的持久性顺序节点:" + persistentSequentialNode);
        System.out.println("创建的临时节点:" + ephemeralNode);

    }

}

获取节点数据

public class getNoteData implements Watcher {
    private static ZooKeeper zooKeeper = null;
    public static void main(String[] args) throws IOException, InterruptedException {
        zooKeeper = new ZooKeeper("8.129.124.193:2181", 5000, new getNoteData());
      //  countDownLatch.await();
        System.out.println("=========Client Connected to zookeeper==========");
        Thread.sleep(Integer.MAX_VALUE);
    }

    @Override
    public void process(WatchedEvent watchedEvent) {
        //当连接创建了,服务端发送给客户端SyncConnected事件
        if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
            System.out.println("连接成功");
            try {
                getNoteData();
                getChildrens();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if(watchedEvent.getType() == Event.EventType.NodeChildrenChanged) {
            try {
                List<String> children = zooKeeper.getChildren(watchedEvent.getPath(), true);
                System.out.println(children);
            } catch (KeeperException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /*
        获取某个节点的内容
     */
    private void getNoteData() throws KeeperException, InterruptedException {

        /**
         * path    : 获取数据的路径
         * watch    : 是否开启监听
         * stat    : 节点状态信息
         *        null: 表示获取最新版本的数据
         *  zk.getData(path, watch, stat);
         */
        byte[] data = zooKeeper.getData("/jerry", false, null);
        System.out.println(new String(data));
    }

    /*
        获取某个节点的子节点列表方法
     */
    public static void getChildrens() throws KeeperException, InterruptedException {
        /*
            path:路径
            watch:是否要启动监听,当子节点列表发生变化,会触发监听
            zooKeeper.getChildren(path, watch);
         */
        List<String> children = zooKeeper.getChildren("/jerry", true);
        System.out.println(children);
    }
}

修改节点数据

public class UpdateNoteData implements Watcher {
    private static ZooKeeper zooKeeper;
    /*
      建立会话
     */
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
     /*
        客户端可以通过创建一个zk实例来连接zk服务器
        new Zookeeper(connectString,sesssionTimeOut,Wather)
        connectString: 连接地址:IP:端口
        sesssionTimeOut:会话超时时间:单位毫秒
        Wather:监听器(当特定事件触发监听时,zk会通过watcher通知到客户端)
     */
         zooKeeper = new ZooKeeper("8.129.124.193:2181", 5000, new UpdateNoteData());
        System.out.println(zooKeeper.getState());

        // 计数工具类:CountDownLatch:不让main方法结束,让线程处于等待阻塞
        //countDownLatch.await();\
        Thread.sleep(Integer.MAX_VALUE);
    }
    /*
        回调方法:处理来自服务器端的watcher通知
     */
    public void process(WatchedEvent watchedEvent) {
        // SyncConnected
        if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
            //解除主程序在CountDownLatch上的等待阻塞
            System.out.println("process方法执行了...");
            // 更新数据节点内容的方法
            try {
                updateNoteSync();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /*
        更新数据节点内容的方法
     */
    private void updateNoteSync() throws Exception {
         /*
            path:路径
            data:要修改的内容 byte[]
            version:为-1,表示对最新版本的数据进行修改
            zooKeeper.setData(path, data,version);
         */
        byte[] data = zooKeeper.getData("/jerry", false, null);
        System.out.println("修改前的值:" + new String(data));

        //修改/lg-persistent 的数据 stat: 状态信息对象
        Stat stat = zooKeeper.setData("/jerry", "客户端修改了节点数据".getBytes("UTF8"), -1);

        byte[] data2 = zooKeeper.getData("/jerry", false, null);
        System.out.println("修改后的值:" + new String(data2));
    }
}

删除节点

public class DeleteNote implements Watcher {
    private static ZooKeeper zooKeeper;
    /*
      建立会话
     */
    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
     /*
        客户端可以通过创建一个zk实例来连接zk服务器
        new Zookeeper(connectString,sesssionTimeOut,Wather)
        connectString: 连接地址:IP:端口
        sesssionTimeOut:会话超时时间:单位毫秒
        Wather:监听器(当特定事件触发监听时,zk会通过watcher通知到客户端)
     */
         zooKeeper = new ZooKeeper("8.129.124.193:2181", 5000, new DeleteNote());
        System.out.println(zooKeeper.getState());
        Thread.sleep(Integer.MAX_VALUE);
    }
    /*
        回调方法:处理来自服务器端的watcher通知
     */
    public void process(WatchedEvent watchedEvent) {
        // SyncConnected
        if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
            //解除主程序在CountDownLatch上的等待阻塞
            System.out.println("process方法执行了...");
            // 删除节点
            try {
                deleteNoteSync();
            } catch (KeeperException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /*
        删除节点的方法
     */
    private void deleteNoteSync() throws KeeperException, InterruptedException {

        /*
      	zooKeeper.exists(path,watch) :判断节点是否存在
      	zookeeper.delete(path,version) : 删除节点
      */
        Stat stat = zooKeeper.exists("/jerry/jerry_child0000000000", false);
        System.out.println(stat == null ? "该节点不存在":"该节点存在");
        if(stat != null){
            zooKeeper.delete("/jerry/jerry_child0000000000",-1);
        }
        Stat stat2 = zooKeeper.exists("/jerry/jerry_child0000000000", false);
        System.out.println(stat2 == null ? "该节点不存在":"该节点存在");
    }
}

Zookeeper-开源客户端

ZkClient
ZkClient是Github上⼀个开源的zookeeper客户端,在Zookeeper原⽣API接⼝之上进⾏了包装,是⼀个更易⽤的Zookeeper客户端,同时,zkClient在内部还实现了诸如Session超时重连、Watcher反复注册等功能接下来,还是从创建会话、创建节点、读取数据、更新数据、删除节点等⽅⾯来介绍如何使⽤zkClient。

添加依赖:

 <dependency>
	 <groupId>com.101tec</groupId>
	 <artifactId>zkclient</artifactId>
	 <version>0.2</version>
 </dependency>

创建会话:

public class CreateSession {
    /*
        借助zkclient完成会话的创建
     */
    public static void main(String[] args) {
        /*
            创建一个zkclient实例就可以完成连接,完成会话的创建
            serverString : 服务器连接地址

            注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
         */
        ZkClient zkClient = new ZkClient("8.129.124.193:2181");
        System.out.println("会话被创建了..");
    }
}

创建节点

public class Create_Note {
    /*
        借助zkclient完成会话的创建
     */
    public static void main(String[] args) {
        /*
            创建一个zkclient实例就可以完成连接,完成会话的创建
            serverString : 服务器连接地址

            注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
         */
        ZkClient zkClient = new ZkClient("8.129.124.193:2181");
        System.out.println("会话被创建了..");

        //创建节点
        /*
            cereateParents : 是否要创建父节点,如果值为true,那么就会递归创建节点
         */
        zkClient.createPersistent("/jerry/jerry_child1",true);
        System.out.println("节点递归创建完成");
    }
}

注意,在原⽣态接⼝中是⽆法创建成功的(⽗节点不存在),但是通过ZkClient通过设置createParents参数为true可以递归的先创建⽗节点,再创建⼦节点。
删除节点
ZkClient提供了递归删除节点的接⼝,即其帮助开发者先删除所有⼦节点(存在),再删除⽗节点。在pom.xml⽂件中添加如下内容。

public class Delete_Note {
    /*
        借助zkclient完成会话的创建
     */
    public static void main(String[] args) {
        /*
            创建一个zkclient实例就可以完成连接,完成会话的创建
            serverString : 服务器连接地址

            注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
         */
        ZkClient zkClient = new ZkClient("8.129.124.193:2181");
        System.out.println("会话被创建了..");
        // 递归删除节点
        String path = "/jerry/jerry_child1";
        zkClient.createPersistent(path+"/c11");
        zkClient.deleteRecursive(path);
        System.out.println("递归删除成功");
    }
}

ZkClient可直接删除带⼦节点的⽗节点,因为其底层先删除其所有⼦节点,然后再删除⽗节点。
获取⼦节点

public class Get_NoteChildren {
    /*
        借助zkclient完成会话的创建
     */
    public static void main(String[] args) throws InterruptedException {
        /*
            创建一个zkclient实例就可以完成连接,完成会话的创建
            serverString : 服务器连接地址

            注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
         */
        ZkClient zkClient = new ZkClient("8.129.124.193:2181");
        System.out.println("会话被创建了..");

        // 获取子节点列表
        List<String> children = zkClient.getChildren("/lg-zkclient");
        System.out.println(children);

        // 注册监听事件
        /*
            客户端可以对一个不存在的节点进行子节点变更的监听
            只要该节点的子节点列表发生变化,或者该节点本身被创建或者删除,都会触发监听
         */
        zkClient.subscribeChildChanges("/lg-zkclient-get", new IZkChildListener() {
            /*
                s : parentPath
                list : 变化后子节点列表
             */
            public void handleChildChange(String parentPath, List<String> list) throws Exception {
                System.out.println(parentPath + "的子节点列表发生了变化,变化后的子节点列表为"+ list);
            }
        });
        //测试
        zkClient.createPersistent("/lg-zkclient-get");
        Thread.sleep(1000);

        zkClient.createPersistent("/lg-zkclient-get/c1");
        Thread.sleep(1000);
    }
}

客户端可以对⼀个不存在的节点进⾏⼦节点变更的监听。⼀旦客户端对⼀个节点注册了⼦节点列表变更监听之后,那么当该节点的⼦节点列表发⽣变更时,服务端都会通知客户端,并将最新的⼦节点列表发送给客户端;该节点本身的创建或删除也会通知到客户端。

获取数据(节点是否存在、更新、删除)

public class Note_API {
    /*
        借助zkclient完成会话的创建
     */
    public static void main(String[] args) throws InterruptedException {
        /*
            创建一个zkclient实例就可以完成连接,完成会话的创建
            serverString : 服务器连接地址

            注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
         */
        ZkClient zkClient = new ZkClient("8.129.124.193:2181");
        System.out.println("会话被创建了..");

        // 判断节点是否存在
        String path = "jerry-ep";
        boolean exists = zkClient.exists(path);

        if(!exists){
            // 创建临时节点
            zkClient.createEphemeral(path,"123");
        }

        // 读取节点内容
        Object o = zkClient.readData(path);
        System.out.println(o);

        // 注册监听
        zkClient.subscribeDataChanges(path, new IZkDataListener() {
            /*
                当节点数据内容发生变化时,执行的回调方法
                s: path
                o: 变化后的节点内容
             */
            public void handleDataChange(String s, Object o) throws Exception {
                System.out.println(s+"该节点内容被更新,更新的内容"+o);
            }
            /*
                当节点被删除时,会执行的回调方法
                s : path
             */
            public void handleDataDeleted(String s) throws Exception {
                System.out.println(s+"该节点被删除");
            }
        });
        // 更新节点内容
        zkClient.writeData(path,"456");
        Thread.sleep(1000);

        // 删除节点
        zkClient.delete(path);
        Thread.sleep(1000);
        
        exists = zkClient.exists(path);
        if(!exists){
            // 创建临时节点
            zkClient.createEphemeral(path,"jerry");
        }
        // 读取节点内容
        o = zkClient.readData(path);
        System.out.println(o);
    }

}

Curator客户端

curator是Netflix公司开源的⼀套Zookeeper客户端框架,和ZKClient⼀样,Curator解决了很多Zookeeper客户端⾮常底层的细节开发⼯作,包括连接重连反复注册WatcherNodeExistsException异常等,是最流⾏的Zookeeper客户端之⼀。从编码⻛格上来讲,它提供了基于Fluent的编程⻛格⽀持

添加依赖

 <dependency>
	 <groupId>org.apache.curator</groupId>
	 <artifactId>curator-framework</artifactId>
	 <version>2.12.0</version>
 </dependency>

创建会话
Curator的创建会话⽅式与原⽣的API和ZkClient的创建⽅式区别很⼤。Curator创建客户端是通过CuratorFrameworkFactory⼯⼚类来实现的。具体如下:
1.使⽤CuratorFramework这个⼯⼚类的两个静态⽅法来创建⼀个客户端

public static CuratorFramework newClient(String connectString, RetryPolicy retryPolicy)
public static CuratorFramework newClient(String connectString, int sessionTimeoutMs, int connectionTimeoutMs, RetryPolicy retryPolicy)

其中参数RetryPolicy提供重试策略的接⼝,可以让⽤户实现⾃定义的重试策略,默认提供了以下实现,分别为ExponentialBackoffRetry(基于backoff的重连策略)、RetryNTimes(重连N次策略)、RetryForever(永远重试策略)。
2.通过调⽤CuratorFramework中的start()⽅法来启动会话

RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",retryPolicy);
client.start();

RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",
 5000,1000,retryPolicy);
client.start();

其实进⼀步查看源代码可以得知,其实这两种⽅法内部实现⼀样,只是对外包装成不同的⽅法。它们的底层都是通过第三个⽅法builder来实现的

RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
private static CuratorFramework Client = CuratorFrameworkFactory.builder()
							 .connectString("server1:2181,server2:2181,server3:2181")
							 .sessionTimeoutMs(50000)
							 .connectionTimeoutMs(30000)
							 .retryPolicy(retryPolicy)
							 .build();
client.start();

参数:

  • connectString:zk的server地址,多个server之间使⽤英⽂逗号分隔开
  • connectionTimeoutMs:连接超时时间,如上是30s,默认是15s
  • sessionTimeoutMs:会话超时时间,如上是50s,默认是60s
  • retryPolicy:失败重试策略
  •  ExponentialBackoffRetry:构造器含有三个参数 ExponentialBackoffRetry(int baseSleepTimeMs, int maxRetries, int maxSleepMs)
     	baseSleepTimeMs:初始的sleep时间,⽤于计算之后的每次重试的sleep时间,
     		计算公式:当前sleep时间=baseSleepTimeMs*Math.max(1,random.nextInt(1<<(retryCount+1)))
     	maxRetries:最⼤重试次数
     	maxSleepMs:最⼤sleep时间,如果上述的当前sleep计算出来⽐这个⼤,那么sleep⽤这个时间,默认的最⼤时间是Integer.MAX_VALUE毫秒。
    
  • start():完成会话的创建

创建节点
curator提供了⼀系列Fluent⻛格的接⼝,通过使⽤Fluent编程⻛格的接⼝,开发⼈员可以进⾏⾃由组合来完成各种类型节点的创建。
下⾯简单介绍⼀下常⽤的⼏个节点创建场景。
(1)创建⼀个初始内容为空的节点

client.create().forPath(path);

Curator默认创建的是持久节点,内容为空
(2)创建⼀个包含内容的节点

client.create().forPath(path,"我是内容".getBytes());

Curator和ZkClient不同的是依旧采⽤Zookeeper原⽣API的⻛格,内容使⽤byte[]作为⽅法参数。
(3)递归创建⽗节点,并选择节点类型

client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path);

creatingParentsIfNeeded这个接⼝⾮常有⽤,在使⽤ZooKeeper 的过程中,开发⼈员经常会碰到NoNodeException 异常,其中⼀个可能的原因就是试图对⼀个不存在的⽗节点创建⼦节点。因此,开发⼈员不得不在每次创建节点之前,都判断⼀下该⽗节点是否存在——这个处理通常⽐较麻烦。在使⽤Curator 之后,通过调⽤creatingParentsIfNeeded 接⼝,Curator 就能够⾃动地递归创建所有需要的⽗节点

public class CreateNote_curator {
    // 创建会话
    public static void main(String[] args) throws Exception {
        //不使用fluent编程风格
        RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);

        // 使用fluent编程风格
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("8.129.124.193:2181")
                .sessionTimeoutMs(50000)
                .connectionTimeoutMs(30000)
                .retryPolicy(exponentialBackoffRetry)
                .namespace("base")  // 独立的命名空间 /base
                .build();

        client.start();
        System.out.println("会话2创建了");

        // 创建节点
        String path = "/jerry-curator/c1";
        String s = client.create().creatingParentsIfNeeded()
                .withMode(CreateMode.PERSISTENT).forPath(path, "init".getBytes());
        System.out.println("节点递归创建成功,该节点路径" + s);
    }
}

删除节点
删除节点的⽅法也是基于Fluent⽅式来进⾏操作,不同类型的操作调⽤ 新增不同的⽅法调⽤即可。
(1)删除⼀个⼦节点

client.delete().forPath(path);

(2)删除节点并递归删除其⼦节点

client.delete().deletingChildrenIfNeeded().forPath(path);

(3)指定版本进⾏删除

client.delete().withVersion(1).forPath(path);

如果此版本已经不存在,则删除异常,异常信息如下。

org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for

(4)强制保证删除⼀个节点

client.delete().guaranteed().forPath(path);

只要客户端会话有效,那么Curator会在后台持续进⾏删除操作,直到节点删除成功。⽐如遇到⼀些⽹络异常的情况,此guaranteed的强制删除就会很有效果。

public class DeleteNote_curator {
    // 创建会话
    public static void main(String[] args) throws Exception {
        // 使用fluent编程风格
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("8.129.124.193:2181")
                .sessionTimeoutMs(50000)
                .connectionTimeoutMs(30000)
                .retryPolicy(exponentialBackoffRetry)
                .namespace("base")  // 独立的命名空间 /base
                .build();
        client.start();
        System.out.println("会话2创建了");
        // 删除节点
        String path = "/jerry-curator";
        client.delete().deletingChildrenIfNeeded().withVersion(-1).forPath(path);

        System.out.println("删除成功,删除的节点" + path);
    }
}

获取数据
获取节点数据内容API相当简单,同时Curator提供了传⼊⼀个Stat变量的⽅式来存储服务器端返回的最新的节点状态信息

// 普通查询
client.getData().forPath(path);
// 包含状态查询
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath(path);
public class GetNote_curator {

    // 创建会话
    public static void main(String[] args) throws Exception {
        //不使用fluent编程风格
        RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
        // 使用fluent编程风格
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("8.129.124.193:2181")
                .sessionTimeoutMs(50000)
                .connectionTimeoutMs(30000)
                .retryPolicy(exponentialBackoffRetry)
                .namespace("base")  // 独立的命名空间 /base
                .build();
        client.start();
        System.out.println("会话2创建了");

        // 创建节点
        String path = "/lg-curator/c1";
        String s = client.create().creatingParentsIfNeeded()
                .withMode(CreateMode.PERSISTENT).forPath(path, "init".getBytes());

        System.out.println("节点递归创建成功,该节点路径" + s);

        // 获取节点的数据内容及状态信息

        // 数据内容
        byte[] bytes = client.getData().forPath(path);
        System.out.println("获取到的节点数据内容:" + new String(bytes));

        // 状态信息
        Stat stat = new Stat();
        client.getData().storingStatIn(stat).forPath(path);
        System.out.println("获取到的节点状态信息:" + stat );
    }
}

更新数据
更新数据,如果未传⼊version参数,那么更新当前最新版本,如果传⼊version则更新指定version,如果version已经变更,则抛出异常。

// 普通更新
client.setData().forPath(path,"新内容".getBytes());
// 指定版本更新
client.setData().withVersion(1).forPath(path);

版本不⼀致异常信息:

org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for
public class UpdateNote_curator {

    // 创建会话
    public static void main(String[] args) throws Exception {
        //不使用fluent编程风格
        RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
        // 使用fluent编程风格
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("8.129.124.193:2181")
                .sessionTimeoutMs(50000)
                .connectionTimeoutMs(30000)
                .retryPolicy(exponentialBackoffRetry)
                .namespace("base")  // 独立的命名空间 /base
                .build();
        client.start();
        System.out.println("会话2创建了");

        // 创建节点
        String path = "/lg-curator/c1";

        // 获取节点的数据内容及状态信息

        // 数据内容
        byte[] bytes = client.getData().forPath(path);
        System.out.println("获取到的节点数据内容:" + new String(bytes));

        // 状态信息
        Stat stat = new Stat(); //0
        client.getData().storingStatIn(stat).forPath(path);

        System.out.println("获取到的节点状态信息:" + stat );

        // 更新节点内容 //1
        int version = client.setData().withVersion(stat.getVersion()).forPath(path, "修改内容1".getBytes()).getVersion();
        System.out.println("当前的最新版本是" + version);
        byte[] bytes2 = client.getData().forPath(path);
        System.out.println("修改后的节点数据内容:" + new String(bytes2));

        // BadVersionException,stat的版本已过期
        client.setData().withVersion(stat.getVersion()).forPath(path,"修改内容2".getBytes());
    }

**curator事件监听

public class watchNote_curator {

    private static CuratorFramework client = null;

    // 创建会话
    public static void main(String[] args) throws Exception {
        //初始话curator
        init();
        watcherTest();
    }

    public static void init() {
        //不使用fluent编程风格

        RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
        // 使用fluent编程风格
        CuratorFramework client = CuratorFrameworkFactory.builder()
                .connectString("8.129.124.193:2181")
                .sessionTimeoutMs(50000)
                .connectionTimeoutMs(30000)
                .retryPolicy(exponentialBackoffRetry)
                .namespace("base")  // 独立的命名空间 /base
                .build();

        client.start();
        System.out.println("会话创建了");
    }

    public static void watcherTest() throws Exception  {
        // 创建节点
        String path = "/jerry/c1";
        Watcher watcher = new Watcher() {
            public void process(WatchedEvent watchedEvent) {
                Event.EventType eventType = watchedEvent.getType();
                if(eventType.equals(Event.EventType.NodeDeleted)){
                    System.out.println("删除节点了--" + watchedEvent.getPath());
                }
            }
        };
        // 创建节点
        client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/jerry/c1");
        client.getChildren().usingWatcher(watcher).forPath("/jerry/c1");
        client.delete().deletingChildrenIfNeeded().withVersion(-1).forPath(path);
    }
}

NodeCache:对一个节点进行监听,监听事件包括指定的路径节点的增、删、改的操作。

	NodeCache nodeCache = new NodeCache(client,path);
    nodeCache.start();
    nodeCache.getListenable().addListener(new NodeCacheListener() {
          @Override
          public void nodeChanged() throws Exception {
               System.out.println("监听事件触发");
               System.out.println("重新获得节点内容为:" + new String(nodeCache.getCurrentData().getData()));
            }
   });

PathChildrenCache: 对指定的路径节点的一级子目录进行监听,不对该节点的操作进行监听,对其子目录的节点进行增、删、改的操作监听

 PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/msg_server_list", false);//监听msg_server_list路径下的所有节点
pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);//异步初始化
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
        @Override
         public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
               PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
               if (type.equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {
                    System.out.println(pathChildrenCacheEvent.getData().getPath());
               }
         }
});

TreeCache: 可以将指定的路径节点作为根节点(祖先节点),对其所有的子节点操作进行监听,呈现树形目录的监听,可以设置监听深度,最大监听深度为2147483647(int类型的最大值)。

TreeCache treeCache = new TreeCache(client, path);
 treeCache.getListenable().addListener(new TreeCacheListener() {
            @Override
            public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
                ChildData eventData = event.getData();
                switch (event.getType()) {
                    case NODE_ADDED:
                        logger.warn(path + "节点添加" + eventData.getPath() + "\t添加数据为:" + new String(eventData.getData()));
                        break;
                    case NODE_UPDATED:
                        logger.warn(eventData.getPath() + "节点数据更新\t更新数据为:" + new String(eventData.getData()) + "\t版本为:" + eventData.getStat().getVersion());
                        break;
                    case NODE_REMOVED:
                        logger.warn(eventData.getPath() + "节点被删除");
                        break;
                    default:
                        break;
                }
            }
        });
treeCache.start();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值