Zookeeper之java api详解

znode是Zookeeper集合的核心组件,Zookeeper api提供了一小组方法使用Zookeeper集合来操纵znode的所有细节。这里没有涉及watch相关的api,另外介绍。

客户端应该遵循以下步骤,以保证与Zookeeper服务器进行清晰干净的交互。

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

需要导入依赖

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

demo代码,每种操作都要同步异步两种模式。

public class ZookeeperDemo implements Watcher{
    private ZooKeeper zooKeeper;


    //路径前缀
    private static final String PATH_PREFIX = "/javaapi";

    //相当于发令枪,会阻塞线程,待得Count变为0时,就唤醒线程。
    CountDownLatch latch = new CountDownLatch(1);

    @Override
    public void process(WatchedEvent watchedEvent) {
        if (watchedEvent.getState().equals(Event.KeeperState.SyncConnected)){
            //如果客户端已经连接到Zookeeper服务器,就会触发SyncConnected事件,进入这里。
            //发令器减1  变为0  被该发令器阻塞的线程将被唤醒
            latch.countDown();
            System.out.println("已连接到客户端");
        }
        if (watchedEvent.getState().equals(Event.KeeperState.Expired)){
            //latch.countDown();
            System.out.println("连接超时");
        }
    }

    @Before
    public void init(){
        try {
            //创建一个Zookeeper客户端并连接到服务器,因为连接过程是异步执行的,所以要配合CountDownLatch保证在发送请求前客户端
            //与服务器已经建立了连接
            //第一个参数:要连接到Zookeeper服务器地址。 第二个参数,session超时,单位毫秒。 第三个参数,为该客户端注册监听。
            zooKeeper = new ZooKeeper("192.168.18.130:2181",5000,this);
            //阻塞线程。CountDownLatch减为0时就会唤醒线程
            latch.await();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @After
    public void destroy(){
        try {
            //关闭连接
            zooKeeper.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步创建节点
     */
    @Test
    public void testAddNodeSync(){
        try {
            //第一个参数  创建节点的路径
            //第二个参数  节点的数据 ,是一个字节数组
            //第三个参数  节点的ACL list列表   ZooDefs.Ids.READ_ACL_UNSAFE代表 world:anyone:adcwr  ,后面会详解。
            //第四个参数   节点的类型
            //返回值是创建的节点的路径

            //创建持久化节点
            String result = zooKeeper.create(PATH_PREFIX + "/PersistentNode","PersistentNode".getBytes(),
                    ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.PERSISTENT);
            System.out.println(result);
            //创建持久化有序节点
            zooKeeper.create(PATH_PREFIX + "/PersistentSeqNode","PersistentSeqNode".getBytes(),
                    ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.PERSISTENT);
            //创建临时节点
            zooKeeper.create(PATH_PREFIX + "/EPHEMERALNode","EPHEMERALNode".getBytes(),
                    ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.EPHEMERAL);
            //创建临时有序节点
            zooKeeper.create(PATH_PREFIX + "/EPHEMERALSeqNode","EPHEMERALSeqNode".getBytes(),
                    ZooDefs.Ids.READ_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * 异步创建节点
     */
    @Test
    public void testAddNodeAsync(){
        //第一个参数  创建节点的路径
        //第二个参数  节点的数据 ,是一个字节数组
        //第三个参数  节点的ACL   ZooDefs.Ids.READ_ACL_UNSAFE代表 world:anyone:adcwr  ,后面会详解。
        //第四个参数   节点的类型
        //第五个参数   节点创建完成(无论成功还是失败)的回调。
        //上下文ctx
        zooKeeper.create(PATH_PREFIX + "/asyncNode", "asyncNode".getBytes(), ZooDefs.Ids.READ_ACL_UNSAFE,
                CreateMode.PERSISTENT, new AsyncCallback.StringCallback() {
                    @Override
                    public void processResult(int rc, String path, Object ctx, String name) {
                        //结果标志,为0时代表节点创建成功
                        System.out.println(rc);
                        //节点的路径
                        System.out.println(path);
                        //上下文参数,就是该create方法传入的最后一个参数
                        System.out.println(ctx);
                        //节点的路径。当创建节点失败时,为null。
                        System.out.println(name);

                    }
                },"aa");
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    //创建节点时赋予特定的ACL
    @Test
    public void testCreateNodeWithACL(){
        //创建ACL访问控制列表
        //第一个参数是权限 1代表 read 2 代表 write 4代表 create 8代表 delete  16代表 admin  相互组合用相加 比如1+2=3 是rw
        //第二个参数 Id对象代表授权模型和授权对象 ,构造函数第一个是授权模型 world、ip、auth、digest  第二个参数是授权对象

        //world:anyone:r
        ACL aclWorld = new ACL(1,new Id("world","anyone"));
        //digest:admin:0uek/hZ/V9fgiM35b0Z2226acMQ=:adcwr
        ACL aclDigest= new ACL(1+2+4+8+16,new Id("digest","admin:0uek/hZ/V9fgiM35b0Z2226acMQ="));
        //ip:192.168.18.128:rw
        ACL aclIP = new ACL(1+2,new Id("ip","192.168.18.128"));
        //把ACL添加到acl列表中,这个就是创建节点要传递的参数
        List<ACL> acls = new ArrayList<>();

        acls.add(aclWorld);
        acls.add(aclDigest);
        acls.add(aclIP);
        try {
            zooKeeper.create(PATH_PREFIX + "/nodeACL","nodeACL".getBytes(),
                    acls,CreateMode.PERSISTENT);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //同步修改节点数据
    @Test
    public void testSetNode(){
        try {
            //第一个参数  修改的节点路径
            //第二个参数  修改的节点数据
            //数据的版本号 ,用于实现乐观锁的,如果此版本号与Zookeeper服务器中的该节点数据的版本号不一样,就会修改失败
            //返回的是修改后节点的元信息,用Stat类封装,与命令 stat path 返回的一致。-1表示该参数不参与修改节点
            Stat stat = zooKeeper.setData(PATH_PREFIX + "/nodeSetData","nodeSetData".getBytes(),-1);
            System.out.println(stat.getVersion());
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //修改节点ACL
    @Test
    public void testSetNodeACL(){
        ACL aclWorld = new ACL(1,new Id("world","anyone"));
        //digest:admin:0uek/hZ/V9fgiM35b0Z2226acMQ=:adcwr
        ACL aclDigest= new ACL(1+2+4+8+16,new Id("digest","admin:0uek/hZ/V9fgiM35b0Z2226acMQ="));
        //ip:192.168.18.128:rw
        ACL aclIP = new ACL(1+2,new Id("ip","192.168.18.128"));
        List<ACL> acls = new ArrayList<>();
        acls.add(aclWorld);
        acls.add(aclDigest);
        acls.add(aclIP);
        try {
            //第一个参数,节点路径
            //第二个参数:要修改的ACL
            //第三个参数aVersion  -1则表示该参数不参与
            zooKeeper.setACL(PATH_PREFIX + "/setACL",acls,-1);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //删除节点
    @Test
    public void testDeleteNode(){

        try {
            //第一个参数:要删除的节点路径
            //第二个参数数据版本,-1表示不参与。
            zooKeeper.delete(PATH_PREFIX + "/nodeDelete",-1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    //查看节点数据
    @Test
    public void getData(){
        Stat stat = new Stat();
        try {
            //第一个参数是节点路径
            //第二个参数是是否注册监听,true的话就会注册创建Zookeeper客户端时传入的监听,第三个是传入stat对象,会把获取到的节点元信息赋值到该对象中。
            //返回值是节点数据的字节数组
            byte[] result = zooKeeper.getData(PATH_PREFIX + "/nodeSetData",false,stat);
            System.out.println(new String(result,"utf-8"));
            System.out.println(stat.getVersion());
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    //获取子节点
    @Test
    public void getChildrenNode(){
        try {
            //第一个参数:节点路径
            //第二个参数:是否注册监听
            //返回值 节点路径列表list。
            List<String> children = zooKeeper.getChildren(PATH_PREFIX, false);
            System.out.println(children);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //查看节点是否存在
    @Test
    public void testNodeExist(){
        try {
            //参数1:节点路径
            //第二个参数:是否注册监听
            //返回值 stat对象,节点的元数据,如果节点不存在就返回null
            Stat exists = zooKeeper.exists("/888", false);
            System.out.println(exists);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值