java zk监听异步_【zookeeper】第4篇:使用客户端API来操作ZK

Java 客户端

pom.xml 文件中引入相关api

org.apache.zookeeper

zookeeper

3.5.4-beta

创建连接

/**

* 创建 zookeeper 会话

*

*

* zookeeper 客户端 和 服务端创建会话的过程是异步的。也就是客户度通过构造方法创建会话后立即返回,此时的连接并没有完全建立。

* 当真正的会话建立完成后,zk服务端会给客户端通知一个事件,客户端获取通知之后在表明连接正在建立。

*/

public class ZooKeeperClientSession implements Watcher {

//用于等待zk服务端通知

private static CountDownLatch latch = new CountDownLatch(1);

public static void main(String[] args) throws Exception {

ZooKeeper zooKeeper = new ZooKeeper("127.0.0.1:2183", 5000, new ZooKeeperClientSession());

System.out.println(zooKeeper.getState());

latch.await();

long sessionId = zooKeeper.getSessionId();

byte[] sessionPasswd = zooKeeper.getSessionPasswd();

System.out.println(zooKeeper.getSessionId());

/**

* 利用 sessionId 和 sessionPasswd 复用会话连接

*/

ZooKeeper zooKeeper1 = new ZooKeeper("127.0.0.1:2183",

5000,

new ZooKeeperClientSession(),

sessionId,

sessionPasswd);

System.out.println(zooKeeper1.getSessionId());

}

/**

* 处理 zookeeper 服务端的 Watcher 通知

* @param watchedEvent

*/

public void process(WatchedEvent watchedEvent) {

System.out.println("receive watch event : " + watchedEvent);

if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {

latch.countDown();

}

}

}

1.构造函数说明

ZooKeeper(String connectString, int sessionTimeout, Watcher watcher)

ZooKeeper(String connectString,

int sessionTimeout,

Watcher watcher,

boolean canBeReadOnly)

ZooKeeper(String connectString,

int sessionTimeout,

Watcher watcher,

long sessionId,

byte[] sessionPasswd)

ZooKeeper(String connectString,

int sessionTimeout,

Watcher watcher,

long sessionId,

byte[] sessionPasswd,

boolean canBeReadOnly)

参数

作用

connectString

zk服务器列表,由英文逗号分开的字符串,例如:127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183;也可以是带有目录的字符:127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183/zk-book

sessionTimeout

会话超时时间,以毫秒为单位。在一个会话周期内,zk客户端和服务端通过心跳来检查连接的有效性,一旦在sessionTimeout时间内没有进行心跳检测,则会话失效

watcher

zk允许客户端在构造方法中传入一个Watcher接口实现类作为事件通知处理器

sessionId、sessionPasswd

利用sessionId 和 sessionPasswd 确保复用会话连接

canBeReadOnly

用于标识当前会话是否支付只读模式。在zk集群模式中,如果一台集群和集群中过半以上的机器都都失去了网络连接,那么这个机器将不再处理客户端请求,包括读写请求。但在某些情况下出现类似问题,我们希望该台机器能够处理读请求,此时为 read-only 模式

创建节点

1.同步创建临时节点

/**

* 同步 api 创建临时节点

*/

public class CreatedSyncNode implements Watcher {

private static CountDownLatch latch = new CountDownLatch(1);

public static void main(String[] args) throws Exception {

ZooKeeper zooKeeper = new ZooKeeper("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183",

5000, new CreatedSyncNode());

latch.await();

//临时节点:创建接口返回该节点路径L,例如返回值 /zk-test

String path = zooKeeper.create("/zk-test", "".getBytes(),

ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);

System.out.println("created path success : " + path);

// 临时顺序节点:会自动的在节点路径后加一个数字,例如返回值:/zk-test0000000001

String path1 = zooKeeper.create("/zk-test", "".getBytes(),

ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

System.out.println("created path success : " + path1);

}

public void process(WatchedEvent watchedEvent) {

if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {

latch.countDown();

}

}

}

2.异步创建节点

/**

* 异步 api 创建持久化节点

*/

public class CreatedAsyncNode implements Watcher {

private static CountDownLatch latch = new CountDownLatch(1);

public static void main(String[] args) throws Exception {

ZooKeeper zooKeeper = new ZooKeeper(

"127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183",

5000,

new CreatedAsyncNode());

latch.await();

//持久化节点:创建接口返回该节点路径,无返回值;异步创建的节点:/zk-test

zooKeeper.create("/zk-test", "".getBytes(),

ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, new CallBack(), "PERSISTENT");

//持久化顺序节点:会自动的在节点路径后加一个数字,该方法无返回值,创建后节点:/zk-test-seq0000000002

zooKeeper.create("/zk-test-seq",

"".getBytes(),

ZooDefs.Ids.OPEN_ACL_UNSAFE,

CreateMode.PERSISTENT_SEQUENTIAL,

new CallBack(),

"PERSISTENT_SEQUENTIAL");

Thread.sleep(1000);

}

public void process(WatchedEvent watchedEvent) {

if (Watcher.Event.KeeperState.SyncConnected == watchedEvent.getState()) {

latch.countDown();

}

}

static class CallBack implements AsyncCallback.StringCallback {

/**

* 服务端回调方法

*

* @param code 服务端响应码:0 接口调用成功;-4 客户端和服务端连接断开;-110 节点已存在 ;-112 会话过期

* @param path 创建节点传入的路径参数

* @param ctx 异步创建api传入的ctx参数

* @param name 服务端真正创建节点的名称,业务逻辑应该以该值为准

*/

public void processResult(int code, String path, Object ctx, String name) {

System.out.println("created success : " + code + "," + path + "," + ctx + "," + name);

}

}

}

读取数据

读取数据包括获取子节点列表和节点的数据内容。zookeeper 中分别提供了 getChildren 和 getData 方法。

方法参数说明

参数名

参数类型

作用

path

String

指定节点的路径

watcher

Watcher

注册一个Watcher,一旦在本次子节点获取到之后,子节点列表发送变更时,那么会向客户端发送通知

watch

boolean

表明是否需要注册一个

stat

org.apache.zookeeper.data.Stat

节点的状态信息,有时候我们不仅需要最新的子节点列表,还要获取这个节点的最新状态信息,我们可以将一个旧的 stat 传入到api方法中,在方法执行过程中 stat 会被来自服务的新的 stat 替换掉

cb

AsyncCallback.ChildrenCallback

异步回调函数

ctx

Object

用于传递上下文信息

同步获取节点列表

/**

* 同步 api 创建节点,然后同步获取节点列表

*/

public class CreatedSyncNode implements Watcher {

private static CountDownLatch latch = new CountDownLatch(1);

private static ZooKeeper zooKeeper;

public static void main(String[] args) throws Exception {

zooKeeper = new ZooKeeper("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183",

5000, new CreatedSyncNode());

latch.await();

String nodePath = "/zk-data";

zooKeeper.create(nodePath, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

List list = zooKeeper.getChildren(nodePath, true);

System.out.println("get children : " + list);

//给节点 /zk-data 再添加子节点 /conf

zooKeeper.create(nodePath + "/conf", "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

Thread.sleep(1000);

}

/**

* 监听子节点的变化

*

* @param watchedEvent

*/

public void process(WatchedEvent watchedEvent) {

if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {

if (Event.EventType.None == watchedEvent.getType() && null == watchedEvent.getPath()) {

latch.countDown();

} else if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged) {

//监听到子节点变化后,主动的去获取节点列表

try {

List list = zooKeeper.getChildren(watchedEvent.getPath(), true);

System.out.println("get children node changed : " + list);

} catch (KeeperException e) {

e.printStackTrace();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

异步获取节点列表

重点是在获取节点列表 api 中传入回调对象,该对象实现 Children2Callback接口

/**

* 异步查询节点列表

*/

public class AsyncQueryNode implements Watcher {

private static CountDownLatch latch = new CountDownLatch(1);

private static ZooKeeper zooKeeper;

public static void main(String[] args) throws Exception {

//创建异步会话

zooKeeper = new ZooKeeper("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183",

5000, new AsyncQueryNode());

latch.await();

String nodePath = "/zk-book";

zooKeeper.create(nodePath, "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

//表示异步获取子节点列表,在 ChildrenCallback 中对节点列表进行处理

zooKeeper.getChildren(nodePath, true, new ChildrenCallback(), "query children");

//给节点 /zk-data 再添加子节点 /conf

zooKeeper.create(nodePath + "/src", "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

Thread.sleep(1000);

}

/**

* 监听子节点的变化

*

* @param watchedEvent

*/

public void process(WatchedEvent watchedEvent) {

if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {

if (Event.EventType.None == watchedEvent.getType() && null == watchedEvent.getPath()) {

latch.countDown();

} else if (watchedEvent.getType() == Event.EventType.NodeChildrenChanged) {

//监听到子节点变化后,主动的去获取节点列表

try {

List list = zooKeeper.getChildren(watchedEvent.getPath(), true);

System.out.println("get children node changed : " + list);

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

static class ChildrenCallback implements AsyncCallback.Children2Callback {

/**

* @param code 服务端响应码

* @param path 创建节点传入的路径参数

* @param ctx 上下文信息

* @param list 子节点列表

* @param stat 节点的状态信息

*/

public void processResult(int code, String path, Object ctx, List list, Stat stat) {

System.out.println("code : " + code

+ ";path : " + path

+ ";ctx : " + ctx

+ ";children list : " + list

+ ";stat : " + stat);

}

}

}

获取节点数据内容方法,getData的用法和getChildren差不多,getData 方法的参数中也有一个 Watcher 参数,该 Watcher 的作用是客户端拿到节点的数据之后,可以进行 Watcher 注册,一旦该节点的状态发送变化,服务端会发送 NoteDataChanged 事件告诉客户端。

同步获取

/**

* 同步获取节点数据

*/

public class SyncGetData implements Watcher {

private static CountDownLatch latch = new CountDownLatch(1);

private static ZooKeeper zooKeeper;

private static Stat stat = new Stat();

public static void main(String[] args) throws Exception {

String path = "/zk-demo";

zooKeeper = new ZooKeeper("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183",

5000,

new SyncGetData());

latch.await();

zooKeeper.create(path, "123".getBytes(),

ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

//直接获取节点数据

byte[] datas = zooKeeper.getData(path, true, stat);

System.out.println("结果:" + new String(datas));

System.out.println(stat);

//修改节点数据

zooKeeper.setData(path, "123".getBytes(), -1);

Thread.sleep(1000);

}

public void process(WatchedEvent watchedEvent) {

if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {

if (Event.EventType.None == watchedEvent.getType() && null == watchedEvent.getPath()) {

latch.countDown();

//节点变化时进行通知,EventType.NodeDataChanged 事件

} else if (watchedEvent.getType() == Event.EventType.NodeDataChanged) {

try {

byte[] datas = zooKeeper.getData(watchedEvent.getPath(), true, stat);

System.out.println("回调通知:" + new String(datas));

System.out.println(stat);

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

}

运行结果:

97b014246cba97cd16c123998c9e7358.png

异步获取

实现异步回调接口 DataCallback,接收回调通知

public class AsyncGetData implements Watcher {

private static CountDownLatch latch = new CountDownLatch(1);

private static ZooKeeper zooKeeper;

public static void main(String[] args) throws Exception {

String path = "/zk-async";

zooKeeper = new ZooKeeper("127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183",

5000,

new AsyncGetData());

latch.await();

zooKeeper.create(path, "456".getBytes(),

ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

//设置异步获取节点数据

zooKeeper.getData(path, true, new DataCallback(), null);

//再次更新节点数据

zooKeeper.setData(path, "789".getBytes(), -1);

Thread.sleep(1000);

}

public void process(WatchedEvent watchedEvent) {

if (Event.KeeperState.SyncConnected == watchedEvent.getState()) {

if (Event.EventType.None == watchedEvent.getType() && null == watchedEvent.getPath()) {

latch.countDown();

//节点变化时进行通知,EventType.NodeDataChanged 事件

} else if (watchedEvent.getType() == Event.EventType.NodeDataChanged) {

try {

//再次异步获取变化后的节点数据

zooKeeper.getData(watchedEvent.getPath(), true, new DataCallback(), null);

} catch (Exception e) {

e.printStackTrace();

}

}

}

}

//接收服务端回调

static class DataCallback implements AsyncCallback.DataCallback {

public void processResult(int code, String path, Object ctx, byte[] data, Stat stat) {

System.out.println("回调通知的节点数据:" + new String(data));

System.out.println("code : " + code + ";path : " + path + ";stat : " + stat);

}

}

}

测试结果:

5baa1f781671472fabf759e4d5cc6b91.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值