Zookeeper Java客户端搭建

目录

一、概述

二、环境搭建

三、创建节点

四、更新节点

五、删除节点

六、查看节点

七、查看子节点

八、总结


一、概述

Zookeeper 的Java客户端API使我们更轻松的去对zookeeper进行各种操作,如创建节点、修改节点值、删除节点等等。

客户端应该遵循以下几个步骤:

  • 连接到zookeeper服务器。zookeeper服务器为客户端分配会话ID。
  • 定期向服务器发送心跳。否则,zookeeper服务器将过期会话ID,客户端需要重新连接。
  • 只要会话ID处于活动状态,就可以获取/设置znode。
  • 所有任务完成后,断开与zookeeper服务器的连接。如果客户端长时间不活动,则zookeeper服务器将自动断开客户端。

本篇文章将会搭建一个简单的示例,来看看如何通过zookeeper客户端实现对服务端的操作。

二、环境搭建

创建一个springboot项目【zookeeper-api-demo】,导入zookeeper依赖。

【a】pom.xml

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>

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

   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
         <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
         </exclusion>
      </exclusions>
   </dependency>
</dependencies>

【b】连接zookeeper服务器

因为连接zk服务器可能需要一些时间,我们可以使用 countDownLatch 阻塞,等待连接成功,控制台输出连接状态。

zookeeper一共有四种构造方法,根据方法参数不同:

  • public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly)
  • public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, long sessionId, byte[] sessionPasswd)
  • public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly)
  • ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)

参数说明如下:

  • connectSstring:连接服务器列表,以“,”分割;
  • sessionTimeout:心跳检测时间周期(毫秒);‘
  • wather:事件监听处理通知器;
  • canBeReadOnly:标识当前会话是否支持只读;
  • sessionld和sessionPasswd:提供连接zookeeper的sessionld和密码, 通过这两个确定唯一一台客户端,目的是可以提供重复会话;

这里我们使用最简单的带三个参数的构造方法创建一个zookeeper对象:

package com.wsh.zookeeper.zookeeperapidemo.zookeper;

import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.concurrent.CountDownLatch;

/**
 * @Description: zookeeper java客户端测试
 * @author: weishihuai
 */
public class ZookeeperDemo {
    /**
     * zookeeper服务器地址
     */
    private static final String CONNECT_STRING = "192.168.179.133:2181";
    /**
     * 会话超时时间
     */
    private static final int SESSION_TIMEOUT = 3000;
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ZookeeperDemo.class);

    public static void main(String[] args) {
        //门闩
        CountDownLatch countDownLatch = new CountDownLatch(1);
        try {
            //创建zookeeper连接
            ZooKeeper zooKeeper = new ZooKeeper(
                    CONNECT_STRING, SESSION_TIMEOUT, watchedEvent -> {
                //获取事件的状态
                Watcher.Event.KeeperState keeperState = watchedEvent.getState();
                Watcher.Event.EventType eventType = watchedEvent.getType();
                //如果是建立连接
                if (Watcher.Event.KeeperState.SyncConnected == keeperState) {
                    if (Watcher.Event.EventType.None == eventType) {
                        logger.info("连接zookeeper成功...");
                        //收到服务端的响应,表示连接zookeeper成功,同时发送信号量,计数器减一,让await阻塞程序继续往下执行
                        countDownLatch.countDown();
                    }
                }
            });

            //阻塞程序
            countDownLatch.await();
            logger.info("客户端连接状态: {}", zooKeeper.getState());
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行main方法,结果如下:

11:23:59.299 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - 连接zookeeper成功...
11:23:59.299 [main] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - 客户端连接状态: CONNECTED

可以看到,我们成功连接到zookeeper服务器端,下面就可以进行创建节点、修改节点、删除节点等操作了。

三、创建节点

创建节点主要分为同步方式和异步方式进行创建:

  • create(String path, byte[] data, List<ACL> acl, CreateMode createMode)    // 同步方式
  • create(String path, byte[] data, List<ACL> acl, CreateMode createMode,AsyncCallback.StringCallback callBack,Object ctx)    // 异步方式

参数说明如下:

  • path - znode路径;
  • data - 要存储在指定znode路径中的数据;
  • acl - 要创建的节点的访问控制列表。zookeeper API提供了一个静态接口ZooDefs.Ids 来获取一些基本的acl列表;
  • createMode - 节点的类型,这是一个枚举,提供四种节点类型:
  1. PERSISTENT (持久节点)
  2. PERSISTENT_SEQUENTIAL (持久顺序节点)
  3. EPHEMERAL (临时节点)
  4. EPHEMERAL_SEQUENTIAL (临时顺序节点)
  • callBack - 异步回调接口;
  • ctx - 传递上下文参数;

案例:

首先在命令行创建/create父节点:

[zk: localhost:2181(CONNECTED) 19] create /create "create"
Created /create
[zk: localhost:2181(CONNECTED) 20] ls /
[zookeeper, create]
package com.wsh.zookeeper.zookeeperapidemo.zookeper;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ZookeeperCreate {

    /**
     * zookeeper服务器地址
     */
    private static final String CONNECT_STRING = "192.168.179.133:2181";
    /**
     * 会话超时时间
     */
    private static final int SESSION_TIMEOUT = 3000;
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ZookeeperDemo.class);
    /**
     * zookeeper对象
     */
    private static ZooKeeper zooKeeper = null;

    static {
        //创建zookeeper连接
        try {
            zooKeeper = new ZooKeeper(
                    CONNECT_STRING, SESSION_TIMEOUT, new CustomWatcher());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    void createNode01() {
        try {
            /**
             * create(String path, byte[] data, List<ACL> acl, CreateMode createMode)
             *  path: 节点的路径
             *  data: 节点的数据
             *  acl: 权限列表 world:anyone:cdrwa
             *  createMode: 节点类型 持久化节点
             */
            zooKeeper.create("/create/node1", "node1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * world授权模式
     */
    void createNode02() {
        // 权限列表 
        List<ACL> aclList = new ArrayList<>();
        // 授权模式和授权对象 
        Id id = new Id("world", "anyone");
        // 权限设置:crdwa
        aclList.add(new ACL(ZooDefs.Perms.READ, id));
        aclList.add(new ACL(ZooDefs.Perms.WRITE, id));
        aclList.add(new ACL(ZooDefs.Perms.DELETE, id));
        aclList.add(new ACL(ZooDefs.Perms.CREATE, id));
        aclList.add(new ACL(ZooDefs.Perms.ADMIN, id));
        try {
            zooKeeper.create("/create/node2", "node2".getBytes(), aclList, CreateMode.PERSISTENT);
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * auth授权模式
     */
    void createNode03() {
        zooKeeper.addAuthInfo("digest", "admin:123456".getBytes());
        // 权限列表
        List<ACL> aclList = new ArrayList<>();
        //授权模式和授权对象
        Id id = new Id("auth", "admin");
        // 权限设置
        aclList.add(new ACL(ZooDefs.Perms.READ, id));
        try {
            zooKeeper.create("/create/node3", "node3".getBytes(), aclList, CreateMode.PERSISTENT);
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * digest授权模式
     */
    void createNode04() {
        // 权限列表
        List<ACL> aclList = new ArrayList<>();
        // 授权模式和授权对象
        Id id = new Id("digest", "admin:0uek/hZ/V9fgiM35b0Z2226acMQ=");
        // 权限设置
        aclList.add(new ACL(ZooDefs.Perms.ALL, id));
        try {
            zooKeeper.create("/create/node4", "node4".getBytes(), aclList, CreateMode.PERSISTENT);
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 异步方式创建节点
     */
    void createNode05() {
        Map<String, Object> callbackParams = new HashMap<>(16);
        callbackParams.put("name", "wsh");
        zooKeeper.create("/create/node5", "node5".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, new AsyncCallback.StringCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, String name) {
                //rc: 0 代表创建成功
                //path: 节点路径
                //ctx: 上下文参数
                //name: 节点路径
                logger.info("rc : {}", rc);
                logger.info("path : {}", path);
                logger.info("ctx : {}", ctx);
                logger.info("name : {}", name);
            }
        }, callbackParams);
     try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ZookeeperCreate zookeeperCreate = new ZookeeperCreate();
        zookeeperCreate.createNode01();
        zookeeperCreate.createNode02();
        zookeeperCreate.createNode03();
        zookeeperCreate.createNode04();
        zookeeperCreate.createNode05();
    }

    static class CustomWatcher implements Watcher {

        @Override
        public void process(WatchedEvent watchedEvent) {
            if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                System.out.println("连接创建成功!");
            }
        }
    }

}

然后打开终端查看对应节点是否创建成功:

[zk: localhost:2181(CONNECTED) 21] ls /
[zookeeper, create]
[zk: localhost:2181(CONNECTED) 22] ls /create
[node4, node5, node2, node3, node1]
[zk: localhost:2181(CONNECTED) 23] get /create/node1
node1
cZxid = 0x8f
ctime = Mon Dec 21 15:32:38 CST 2020
mZxid = 0x8f
mtime = Mon Dec 21 15:32:38 CST 2020
pZxid = 0x8f
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 24] get /create/node2
node2
cZxid = 0x90
ctime = Mon Dec 21 15:32:38 CST 2020
mZxid = 0x90
mtime = Mon Dec 21 15:32:38 CST 2020
pZxid = 0x90
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 25] get /create/node3
node3
cZxid = 0x91
ctime = Mon Dec 21 15:32:38 CST 2020
mZxid = 0x91
mtime = Mon Dec 21 15:32:38 CST 2020
pZxid = 0x91
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 26] get /create/node4
node4
cZxid = 0x92
ctime = Mon Dec 21 15:32:38 CST 2020
mZxid = 0x92
mtime = Mon Dec 21 15:32:38 CST 2020
pZxid = 0x92
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0
[zk: localhost:2181(CONNECTED) 27] get /create/node5
node5
cZxid = 0x93
ctime = Mon Dec 21 15:32:38 CST 2020
mZxid = 0x93
mtime = Mon Dec 21 15:32:38 CST 2020
pZxid = 0x93
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 5
numChildren = 0

四、更新节点

zookeeper中,跟创建节点一样,同样支持同步和异步两种方式更新节点的值:

  • setData(String path, byte[] data, int version) // 同步方式
  • setData(String path, byte[] data, int version,AsyncCallback.StatCallback callBack, Object ctx) // 异步方式

参数说明如下:

  • path - znode路径;
  • data - 要存储在指定znode路径中的数据;
  • version - znode的当前版本。每当数据更改时,ZooKeeper会更新znode的版本号;
  • callBack - 异步回调接口;
  • ctx - 传递上下文参数;

案例:

首先得在终端上创建两个节点:

[zk: localhost:2181(CONNECTED) 29] create /set "set"
Created /set
[zk: localhost:2181(CONNECTED) 30] create /set/node1 "node1"
Created /set/node1
[zk: localhost:2181(CONNECTED) 31] create /set/node2 "node2"
Created /set/node2
[zk: localhost:2181(CONNECTED) 32] ls /set
[node2, node1]
package com.wsh.zookeeper.zookeeperapidemo.zookeper;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class ZookeeperUpdate {

    /**
     * zookeeper服务器地址
     */
    private static final String CONNECT_STRING = "192.168.179.133:2181";
    /**
     * 会话超时时间
     */
    private static final int SESSION_TIMEOUT = 3000;
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ZookeeperDemo.class);
    /**
     * zookeeper对象
     */
    private static ZooKeeper zooKeeper = null;

    static {
        //创建zookeeper连接
        try {
            zooKeeper = new ZooKeeper(
                    CONNECT_STRING, SESSION_TIMEOUT, new CustomWatcher());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    void set01() {
        try {
            /**
             * setData(String path, byte[] data, int version)
             * path: 节点的路径
             * data: 节点更新值
             * version: 节点版本号  -1代表版本号不作为修改条件
             */
            zooKeeper.setData("/set/node1", "node11".getBytes(), -1);
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    void set02() {
        zooKeeper.setData("/set/node2", "node22".getBytes(), -1, new AsyncCallback.StatCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, Stat stat) {
                // 0 代表修改成功
                logger.info("rc: {}", rc);
                // 节点路径
                logger.info("path: {}", path);
                // 上下文参数
                logger.info("ctx: {}", ctx);
                // 节点属性信息
                logger.info("version: {}", stat.getVersion());
                logger.info("ctime: {}", stat.getCtime());
            }
        }, "this is callback params");
       try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        ZookeeperUpdate zookeeperUpdate = new ZookeeperUpdate();
        zookeeperUpdate.set01();
        zookeeperUpdate.set02();
    }

    static class CustomWatcher implements Watcher {

        @Override
        public void process(WatchedEvent watchedEvent) {
            if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                System.out.println("连接创建成功!");
            }
        }
    }

}

运行程序,我们通过终端查看节点的值是否更新成功:

[zk: localhost:2181(CONNECTED) 33] get /set/node1
node11
cZxid = 0x96
ctime = Mon Dec 21 16:25:57 CST 2020
mZxid = 0x99
mtime = Mon Dec 21 16:28:38 CST 2020
pZxid = 0x96
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0
[zk: localhost:2181(CONNECTED) 34] get /set/node2
node22
cZxid = 0x97
ctime = Mon Dec 21 16:26:04 CST 2020
mZxid = 0x9a
mtime = Mon Dec 21 16:28:38 CST 2020
pZxid = 0x97
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 6
numChildren = 0

可见,节点的值成功更新。

五、删除节点

zookeeper删除节点同样直接两种方式:同步方式和异步方式。

  • delete(String path, int version) // 同步方式
  • delete(String path, int version, AsyncCallback.VoidCallback callBack, Object ctx) // 异步方式

参数说明如下:

  • path - 节点路径;
  • version - 节点数据的当前版本;
  • callBack - 异步回调接口;
  • ctx - 异步回调上下文参数;

案例:

首先终端上面创建两个节点:

[zk: localhost:2181(CONNECTED) 36] create /delete "delete"
Created /delete
[zk: localhost:2181(CONNECTED) 37] create /delete/node1 "node1" 
Created /delete/node1
[zk: localhost:2181(CONNECTED) 38] create /delete/node2 "node2"
Created /delete/node2
package com.wsh.zookeeper.zookeeperapidemo.zookeper;

import org.apache.zookeeper.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class ZookeeperDelete {

    /**
     * zookeeper服务器地址
     */
    private static final String CONNECT_STRING = "192.168.179.133:2181";
    /**
     * 会话超时时间
     */
    private static final int SESSION_TIMEOUT = 3000;
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ZookeeperDemo.class);
    /**
     * zookeeper对象
     */
    private static ZooKeeper zooKeeper = null;

    static {
        //创建zookeeper连接
        try {
            zooKeeper = new ZooKeeper(
                    CONNECT_STRING, SESSION_TIMEOUT, new CustomWatcher());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步方式
     */
    void delete01() {
        try {
            /**
             * delete(String path, int version)
             * path: 节点路径
             * version: 节点数据版本号
             */
            zooKeeper.delete("/delete/node1", -1);
        } catch (InterruptedException | KeeperException e) {
            e.printStackTrace();
        }
    }

    /**
     * 异步方式
     */
    void delete02() {
        zooKeeper.delete("/delete/node2", -1, new AsyncCallback.VoidCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx) {
                // 0代表删除成功
                logger.info("rc: {}", rc);
                // 节点的路径
                logger.info("path: {}", path);
                // 上下文参数对象
                logger.info("ctx: {}", ctx);
            }
        }, "this is callback params");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        ZookeeperDelete zookeeperDelete = new ZookeeperDelete();
        zookeeperDelete.delete01();
        zookeeperDelete.delete02();
    }

    static class CustomWatcher implements Watcher {

        @Override
        public void process(WatchedEvent watchedEvent) {
            if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                System.out.println("连接创建成功!");
            }
        }
    }

}

运行程序,执行完后,使用终端查看节点是否已删除:

[zk: localhost:2181(CONNECTED) 39] ls /delete 
[]

六、查看节点

在zookeeper中,查看节点同样支持同步和异步方式。

  • getData(String path, boolean b, Stat stat) // 同步方式
  • getData(String path, boolean b,AsyncCallback.DataCallback callBack,Object ctx) // 异步方式

参数说明:

  • path - znode路径;
  • b - 是否使用连接对象中注册的监视器;
  • stat - 返回znode的元数据;
  • callBack - 异步回调接口;
  • ctx - 传递上下文参数;

案例:

首先使用终端创建两个节点:

[zk: localhost:2181(CONNECTED) 40] create /read "read"
Created /read
[zk: localhost:2181(CONNECTED) 41] create /read/node1 "node1"
Created /read/node1
[zk: localhost:2181(CONNECTED) 42] create /read/node2 "node2"
Created /read/node2
[zk: localhost:2181(CONNECTED) 43] ls /read
[node2, node1]
package com.wsh.zookeeper.zookeeperapidemo.zookeper;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

public class ZookeeperRead {

    /**
     * zookeeper服务器地址
     */
    private static final String CONNECT_STRING = "192.168.179.133:2181";
    /**
     * 会话超时时间
     */
    private static final int SESSION_TIMEOUT = 3000;
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ZookeeperDemo.class);
    /**
     * zookeeper对象
     */
    private static ZooKeeper zooKeeper = null;

    static {
        //创建zookeeper连接
        try {
            zooKeeper = new ZooKeeper(
                    CONNECT_STRING, SESSION_TIMEOUT, new CustomWatcher());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步方式
     */
    void read01() {
        try {
            Stat stat = new Stat();
            byte[] data = zooKeeper.getData("/read/node1", false, stat);
            logger.info("data :{}", new String(data));
            logger.info("version :{}", stat.getVersion());
            logger.info("ctime :{}", stat.getCtime());
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 异步方式
     */
    void read02() {
        zooKeeper.getData("/read/node2", false, new AsyncCallback.DataCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
                // 0代表读取成功
                logger.info("rc :{}", rc);
                // 节点的路径
                logger.info("path :{}", path);
                // 上下文参数对象
                logger.info("ctx :{}", ctx);
                // 数据
                logger.info("data :{}", new String(data));
                // 属性对象
                logger.info("version :{}", stat.getVersion());
            }
        }, "this is callback params");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        ZookeeperRead zookeeperRead = new ZookeeperRead();
        zookeeperRead.read01();
        zookeeperRead.read02();
    }

    static class CustomWatcher implements Watcher {

        @Override
        public void process(WatchedEvent watchedEvent) {
            if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                System.out.println("连接创建成功!");
            }
        }
    }

}

观察后端日志,可以看到,成功读取到节点的数据。

16:46:35.429 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - rc :0
16:46:35.429 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - path :/read/node2
16:46:35.429 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - ctx :this is callback params
16:46:35.429 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - data :node2
16:46:35.429 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - version :0

七、查看子节点

  • getChildren(String path, boolean b) // 同步方式
  • getChildren(String path, boolean b,AsyncCallback.ChildrenCallback callBack,Object ctx) // 异步方式

参数说明如下:

  • path - Znode路径;
  • b - 是否使用连接对象中注册的监视器;
  • callBack - 异步回调接口;
  • ctx - 传递上下文参数;

案例:

首先在终端创建两个节点:

[zk: localhost:2181(CONNECTED) 44] create /children "children"
Created /children
[zk: localhost:2181(CONNECTED) 45] create /children/node1 "node1"   
Created /children/node1
[zk: localhost:2181(CONNECTED) 46] create /children/node2 "node2"
Created /children/node2
[zk: localhost:2181(CONNECTED) 47] ls /children
[node2, node1]
package com.wsh.zookeeper.zookeeperapidemo.zookeper;

import org.apache.zookeeper.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

public class ZookeeperChildren {

    /**
     * zookeeper服务器地址
     */
    private static final String CONNECT_STRING = "192.168.179.133:2181";
    /**
     * 会话超时时间
     */
    private static final int SESSION_TIMEOUT = 3000;
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(ZookeeperDemo.class);
    /**
     * zookeeper对象
     */
    private static ZooKeeper zooKeeper = null;

    static {
        //创建zookeeper连接
        try {
            zooKeeper = new ZooKeeper(
                    CONNECT_STRING, SESSION_TIMEOUT, new CustomWatcher());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步方式
     */
    void getChildren01() {
        List<String> children;
        try {
            children = zooKeeper.getChildren("/children", false);
            for (String child : children) {
                logger.info("节点:" + child);
            }
        } catch (KeeperException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 异步方式
     */
    void getChildren02() {
        zooKeeper.getChildren("/children", false, new AsyncCallback.ChildrenCallback() {
            @Override
            public void processResult(int rc, String path, Object ctx, List<String> children) {
                // 0代表读取成功
                logger.info("rc :{}", rc);
                // 节点的路径
                logger.info("path :{}", path);
                // 上下文参数对象
                logger.info("ctx :{}", ctx);
                for (String child : children) {
                    logger.info("节点:" + child);
                }
            }
        }, "this is callback params");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        ZookeeperChildren zookeeperChildren = new ZookeeperChildren();
        zookeeperChildren.getChildren01();
        zookeeperChildren.getChildren02();
    }

    static class CustomWatcher implements Watcher {

        @Override
        public void process(WatchedEvent watchedEvent) {
            if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
                System.out.println("连接创建成功!");
            }
        }
    }

}

观察后端日志,可见成功查询出节点对应的所有子节点信息:

16:54:08.926 [main] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - 节点:node2
16:54:08.926 [main] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - 节点:node1
16:54:08.928 [main-SendThread(192.168.179.133:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply sessionid:0x1000003ec2f000a, packet:: clientPath:/children serverPath:/children finished:false header:: 2,8  replyHeader:: 2,171,0  request:: '/children,F  response:: v{'node2,'node1} 
16:54:08.929 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - rc :0
16:54:08.930 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - path :/children
16:54:08.930 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - ctx :this is callback params
16:54:08.930 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - 节点:node2
16:54:08.930 [main-EventThread] INFO com.wsh.zookeeper.zookeeperapidemo.zookeper.ZookeeperDemo - 节点:node1

八、总结

本篇文章主要总结了我们如何使用原生API去连接zookeeper服务器端,然后使用客户端API去进行一些操作,如新增节点、修改节点等。当然还有一些开源框架对zookeeper进行了封装,如Curator,它解决了很多 Zookeeper 客户端非常底层的细节开发工作,包括连接重连、反复注册 Watcher 和 NodeExistsException 异常等,感兴趣的小伙伴可以去学习一下。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值