前言
GitHub:https://github.com/yihonglei/ZooKeeper-Study
本文采用zk原生客户端方式对zk进行操作,对应github的zk-client项目。
maven引入jar包:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
一 zkClient
ZkClient 是由 Datameer 的工程师开发的开源客户端,对 Zookeeper 的原生 API 进行了包 装,实现了超时重连、
Watcher 反复注册等功能。
二 zkClient操作znode
实例代码:
package com.lanhuigu.zookeeper.znode;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.serialize.SerializableSerializer;
import java.io.Serializable;
import java.util.List;
/**
* ZkClient 进行CRUD操作。
*
* @auther: yihonglei
* @date: 2019-05-14 17:09
*/
public class ZkClientCrud<T> {
private String connectString = "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183";
private ZkClient zkClient;
public ZkClientCrud() {
this.zkClient = new ZkClient(connectString, 5000,
5000, new SerializableSerializer());
}
/**
* 创建持久节点
*/
public void createPersistent(String path, Object data) {
zkClient.createPersistent(path, data);
}
/**
* 递归创建持久节点
*/
public void createPersistent(String path, boolean createParents) {
zkClient.createPersistent(path, createParents);
}
/**
* 读取信息
*/
public T readData(String path) {
return zkClient.readData(path);
}
/**
* 获取子节点列表
*/
public List<String> getChildren(String path) {
return zkClient.getChildren(path);
}
/**
* 数据写入节点
*/
public void writeData(String path, Object object) {
zkClient.writeData(path, object);
}
/**
* 删除节点
*/
public void delete(String path) {
zkClient.delete(path);
}
/**
* 判断节点是否存在
*/
public boolean exists(String path) {
return zkClient.exists(path);
}
/**
* 递归删除节点
*/
public void deleteRecursive(String path) {
zkClient.deleteRecursive(path);
}
/**
* 用户实体,需要序列化
*/
public static class User implements Serializable {
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
/**
* 测试
*/
public static void main(String[] args) {
ZkClientCrud client = new ZkClientCrud();
// ------ 1、存储单个值 -------
String path = "/lanhuiguZkClient";
// 判断节点是否存在
if (client.exists(path)) {
client.delete(path);
}
// 创建节点
client.createPersistent(path, "2019");
// 读取数据
String data = client.readData(path).toString();
System.out.println("存储单个值readData:" + data);
// ------ 2、存储对象 -------
String pathObj = "/lanhuiguZkClientObj";
// 判断节点是否存在
if (client.exists(pathObj)) {
client.delete(pathObj);
}
// 创建节点
User user = new User();
user.setUserName("root");
user.setPassword("123456");
client.createPersistent(pathObj, user);
// 读取数据
System.out.println("存储对象readData:" + client.readData(pathObj));
}
}
三 zkClient操作watcher
zkClient封装了三种重要的注册监听。
接口类 | 注册监听方法 | 解除监听方法 |
IZkChildListener (子节点) |
ZkClient 的 subscribeChildChanges 方法 |
ZkClient 的 unsubscribeChildChanges 方法 |
IZkDataListener (数据) |
ZkClient 的 subscribeDataChanges 方法 |
ZkClient 的 unsubscribeDataChanges 方法 |
IZkStateListener (客户端状 态) |
ZkClient 的 subscribeStateChanges 方 法 |
ZkClient 的 unsubscribeStateChanges 方法 |
在 ZkClient 中客户端可以通过注册相关的事件监听来实现对 Zookeeper 服务端时间的订阅。
package com.lanhuigu.zookeeper.watcher;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.IZkStateListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.serialize.SerializableSerializer;
import org.apache.zookeeper.Watcher;
import java.util.List;
/**
* ZkClient 进行watcher操作。
*
* @auther: yihonglei
* @date: 2019-05-14 17:09
*/
public class ZkClientWatcher<T> {
private String connectString = "127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183";
private ZkClient zkClient;
public ZkClientWatcher() {
this.zkClient = new ZkClient(connectString, 5000, 5000, new SerializableSerializer());
}
/**
* 读取信息
*/
public T readData(String path) {
return zkClient.readData(path);
}
/**
* 获取子节点列表
*/
public List<String> getChildren(String path) {
return zkClient.getChildren(path);
}
/**
* 数据写入节点
*/
public void writeData(String path, Object object) {
zkClient.writeData(path, object);
}
/**
* 创建持久节点
*/
public void createPersistent(String path, Object data) {
zkClient.createPersistent(path, data);
}
/**
* 递归创建持久节点
*/
public void createPersistent(String path, boolean createParents) {
zkClient.createPersistent(path, createParents);
}
/**
* 判断节点是否存在
*/
public boolean exists(String path) {
return zkClient.exists(path);
}
/**
* 删除节点
*/
public void delete(String path) {
zkClient.delete(path);
}
/**
* 递归删除节点
*/
public void deleteRecursive(String path) {
zkClient.deleteRecursive(path);
}
/**
* 节点添加监听
*/
public void listener(String path) {
// 对当前节点数据改变进行监听
zkClient.subscribeDataChanges(path, new IZkDataListener() {
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println("【变更节点】dataPath: " + dataPath + ", data: " + data);
}
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("【删除节点】dataPath: " + dataPath);
}
});
// 对当前节点的子节点改变进行监听
zkClient.subscribeChildChanges(path, new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
System.out.println("【子节点改变监听】parentPath: " + parentPath + ", currentChilds: " + currentChilds);
}
});
// 对当前节点状态变化进行监听
zkClient.subscribeStateChanges(new IZkStateListener() {
@Override
public void handleStateChanged(Watcher.Event.KeeperState state) throws Exception {
if (state == Watcher.Event.KeeperState.SyncConnected) {
// 当重新启动后start,监听触发
System.out.println("连接成功");
} else if (state == Watcher.Event.KeeperState.Disconnected) {
System.out.println("连接断开");// 当在服务端将zk服务stop时,监听触发
} else {
System.out.println("其他状态" + state);
}
}
@Override
public void handleNewSession() throws Exception {
System.out.println("重建session");
}
@Override
public void handleSessionEstablishmentError(Throwable error) throws Exception {
}
});
}
/**
* 测试代码
*/
public static void main(String[] args) throws InterruptedException {
ZkClientWatcher zkClientWatcher = new ZkClientWatcher();
String path = "/lanhuiguZkClientWatcher";
// 启动监听
zkClientWatcher.listener(path);
// 删除节点
if (zkClientWatcher.exists(path)) {
zkClientWatcher.deleteRecursive(path);
}
// 创建节点
zkClientWatcher.createPersistent(path, "2019");
// 休眠
Thread.sleep(2000);
// 写操作
zkClientWatcher.writeData(path, "2019-new");
// 让主线程一直休眠,不断掉
Thread.sleep(Integer.MAX_VALUE);
}
}
监听处理注册后,节点发生改变,触发相应的事件。