Java 客户端框架
Zookeeper 原生客户端
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>enjoy</groupId>
<artifactId>zookeeperJavaApi</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.12</version>
</dependency>
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
创建会话
public class TestCreateSession {
// zookeeper服务器地址
private static final String SERVER = "192.168.71.128:2181";
// 回话超时
private final int SESSION_TIMEOUT = 30000;
//发令枪
private CountDownLatch countDownLatch = new CountDownLatch(1);
/**
* 获得 session 的方式,这种方式可能会在 ZooKeeper 还没有获得连接的时候就已经对 ZK 进行访问了
*/
@Test
public void testSession1() throws Exception {
ZooKeeper zooKeeper = new ZooKeeper(SERVER, SESSION_TIMEOUT, null);
System.out.println(zooKeeper);
System.out.println(zooKeeper.getState()); // CONNECTING
}
/**
* 对获得 Session 的方式进行优化,在 ZooKeeper 初始化完成以前先等待,等待完成后再进行后续操作
*/
@Test
public void testSession2() throws Exception {
ZooKeeper zooKeeper = new ZooKeeper(SERVER, SESSION_TIMEOUT, new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
if (watchedEvent.getState() == Event.KeeperState.SyncConnected) {
//确认已经连接完毕后再进行操作
countDownLatch.countDown();
System.out.println("已经获得了连接");
}
}
});
//连接完成之前先等待
countDownLatch.await(); // 等待连接成功的发令枪
System.out.println(zooKeeper.getState()); // CONNECTED
}
}
客户端基本操作
public class TestJavaApi implements Watcher {
private static final int SESSION_TIMEOUT = 10000;
private static final String CONNECTION_STRING = "192.168.71.128:2181";
private static final String ZK_PATH = "/leader";
private ZooKeeper zooKeeper = null;
private CountDownLatch connectedSemaphore = new CountDownLatch(1);
public static void main(String[] args) {
TestJavaApi sample = new TestJavaApi();
sample.createConnection(CONNECTION_STRING, SESSION_TIMEOUT); // 创建session
if (sample.createPath(ZK_PATH, "我是节点初始内容")) { // 创建节点
System.out.println();
System.out.println("数据内容: " + sample.readData(ZK_PATH) + "\n"); // 读取数据
sample.writeData(ZK_PATH, "更新后的数据"); // 更新数据
System.out.println("数据内容: " + sample.readData(ZK_PATH) + "\n");
sample.deleteNode(ZK_PATH); // 删除数据
}
sample.releaseConnection(); // 释放session连接
}
public void createConnection(String connectString, int sessionTimeout) {
this.releaseConnection();
try {
zooKeeper = new ZooKeeper(connectString, sessionTimeout, this); // 创建zookeeper
connectedSemaphore.await(); // 等待发令信号: session创建成功
} catch (InterruptedException e) {
System.out.println("连接创建失败,发生 InterruptedException"); // 被中断
e.printStackTrace();
} catch (IOException e) {
System.out.println("连接创建失败,发生 IOException"); // 可能是超时
e.printStackTrace();
}
}
public void releaseConnection() { // 关闭 ZK 连接
if (null != this.zooKeeper) {
try {
this.zooKeeper.close();
} catch (InterruptedException e) {
// ignore e.printStackTrace();
}
}
}
public boolean createPath(String path, String data) {
try {
String actualPath = this.zooKeeper.create(
path, // 节点路径: the actual path of the created node
data.getBytes(), // 节点内容
Ids.OPEN_ACL_UNSAFE, // 节点权限
CreateMode.EPHEMERAL // 节点类型: PERSISTENT PERSISTENT_SEQUENTIAL EPHEMERAL EPHEMERAL_SEQUENTIAL
);
System.out.println("节点创建成功, Path: " + actualPath + ", content: " + data);
} catch (KeeperException e) {
System.out.println("节点创建失败,发生 KeeperException");
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("节点创建失败,发生 InterruptedException");
e.printStackTrace();
}
return true;
}
public String readData(String path) {
try {
System.out.println("获取数据成功,path:" + path);
return new String(this.zooKeeper.getData(path, false, null));
} catch (KeeperException e) {
System.out.println("读取数据失败,发生 KeeperException,path: " + path);
e.printStackTrace();
return "";
} catch (InterruptedException e) {
System.out.println("读取数据失败,发生 InterruptedException,path: " + path);
e.printStackTrace();
return "";
}
}
public boolean writeData(String path, String data) { // 更新指定节点数据内容
try {
System.out.println("更新数据成功,path:" + path + ", stat: " +
this.zooKeeper.setData(path, data.getBytes(), -1) // 更新
);
} catch (KeeperException e) {
System.out.println("更新数据失败,发生 KeeperException,path: " + path);
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("更新数据失败,发生 InterruptedException,path: " + path);
e.printStackTrace();
}
return false;
}
public void deleteNode(String path) { // 删除指定节点
try {
this.zooKeeper.delete(path, -1);
System.out.println("删除节点成功,path:" + path);
} catch (KeeperException e) {
System.out.println("删除节点失败,发生 KeeperException,path: " + path);
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println("删除节点失败,发生 InterruptedException,path: " + path);
e.printStackTrace();
}
}
@Override
public void process(WatchedEvent event) { // 收到来自 Server 的 Watcher 通知后的处理。
System.out.println("收到事件通知:" + event.getState() + "\n");
if (Event.KeeperState.SyncConnected == event.getState()) {
connectedSemaphore.countDown();
}
}
}
Watch机制
public class ZooKeeperWatcher implements Watcher {
private static final int SESSION_TIMEOUT = 10000; // 定义 session 失效时间
private static final String CONNECTION_ADDR = "192.168.71.128:2181";
private static final String PARENT_PATH = "/testWatch"; // 父路径设置
private static final String CHILDREN_PATH = "/testWatch/children";
private static final String LOG_PREFIX_OF_MAIN = "【Main】"; // 进入标识
AtomicInteger seq = new AtomicInteger(); // 定义原子变量
private ZooKeeper zk = null; // zk 变量
// 信号量设置,用于等待 zookeeper 连接建立之后 通知阻塞程序继续向下执行
private final CountDownLatch connectedSemaphore = new CountDownLatch(1);
public static void main(String[] args) throws Exception {
//建立 watcher
ZooKeeperWatcher zkWatch = new ZooKeeperWatcher();
//创建连接
zkWatch.createConnection(CONNECTION_ADDR, SESSION_TIMEOUT);
System.out.println(zkWatch.zk.toString());
Thread.sleep(1000);
// 清理节点
zkWatch.deleteAllTestPath();
if (zkWatch.createPath(PARENT_PATH, System.currentTimeMillis() + "")) { // 创建节点
// 读取数据,在操作节点数据之前先调用 zookeeper 的 getData()方法是为了可以 watch 到对节点的操作。【watch 是一次性的】,
// 也就是说,如果第二次又重新调用了 setData()方法,在此之前需要重新调
System.out.println("---------------------- read parent ----------------------------");
zkWatch.readData(PARENT_PATH, true);
// 更新数据
zkWatch.writeData(PARENT_PATH, System.currentTimeMillis() + "");
// 读取子节点,设置对子节点变化的 watch,如果不写该方法,则在创建子节点是只会输出 NodeCreated,而不会输出 NodeChildrenChanged,
// 也就是说创建子节点时没有 watch。
// 如果是递归的创建子节点,如 path="/p/c1/c2"的话,getChildren(PARENT_PATH,
// ture)只会在创建 c1 时 watch,输出 c1 的 NodeChildrenChanged,
// 而 不 会 输 出 创 建 c2 时 的 NodeChildrenChanged , 如 果 watch 到 c2 的
// NodeChildrenChanged,则需要再调用一次 getChildren(String path, true)方法, 其中 path="/p/c1"
System.out.println("---------------------- read children path ----------------------------");
zkWatch.getChildren(PARENT_PATH, true);
Thread.sleep(1000);
// 创建子节点,同理如果想要 watch 到 NodeChildrenChanged 状态,需要调用getChildren(CHILDREN_PATH, true)
zkWatch.createPath(CHILDREN_PATH, System.currentTimeMillis() + "");
Thread.sleep(1000);
zkWatch.readData(CHILDREN_PATH, true);
zkWatch.writeData(CHILDREN_PATH, System.currentTimeMillis() + "");
}
Thread.sleep(50000);
// 清理节点
zkWatch.deleteAllTestPath();
Thread.sleep(1000);
zkWatch.releaseConnection();
}
public void createConnection(String connectAddr, int sessionTimeout) {
this.releaseConnection();
try {
zk = new ZooKeeper(connectAddr, sessionTimeout, this); // 创建zookeeper
System.out.println(LOG_PREFIX_OF_MAIN + "开始连接 ZK 服务器");
connectedSemaphore.await(); // 等待session创建成功
} catch (Exception e) {
e.printStackTrace();
}
}
public void releaseConnection() { // 关闭 ZK 连接
if (this.zk != null) {
try {
this.zk.close();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public boolean createPath(String path, String data) { // 创建节点
try {
// 设置监控(由于 zookeeper 的监控都是一次性的所以每次必须设置监控)
this.zk.exists(path, true);
System.out.println(LOG_PREFIX_OF_MAIN + "节点创建成功, Path: " + this.zk.create(
path, // 路径
data.getBytes(), // 数 据
ZooDefs.Ids.OPEN_ACL_UNSAFE, // 所 有 可 见
CreateMode.PERSISTENT) + // 永 久 存 储
", content: " + data);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public String readData(String path, boolean needWatch) { // 读取指定节点数据内容
try {
return new String(this.zk.getData(path, needWatch, null)); // 读取并重新设置监听
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
public boolean writeData(String path, String data) { // 更新指定节点数据内容
try {
// 更新数据不需要重新设置监听
System.out.println("更新数据成功,path:" + path + ", stat: " + this.zk.setData(path, data.getBytes(), -1));
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public void deleteNode(String path) { // 删除指定节点
try {
this.zk.delete(path, -1);
System.out.println(LOG_PREFIX_OF_MAIN + "删除节点成功,path:" + path);
} catch (Exception e) {
e.printStackTrace();
}
}
public Stat exists(String path, boolean needWatch) { // 判断指定节点是否存在
try {
return this.zk.exists(path, needWatch);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private List<String> getChildren(String path, boolean needWatch) { // 获取子节点
try {
return this.zk.getChildren(path, needWatch);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void deleteAllTestPath() { // 删除所有节点
if (this.exists(CHILDREN_PATH, false) != null) {
this.deleteNode(CHILDREN_PATH);
} // 先删除子,再删除父
if (this.exists(PARENT_PATH, false) != null) {
this.deleteNode(PARENT_PATH);
}
}
@Override // 一个钩子方法
public void process(WatchedEvent event) { // 收到来自 Server 的 Watcher 通知后的处理。
System.out.println("进入 process 。。。。。event = " + event);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (event == null) {
return;
}
Watcher.Event.KeeperState keeperState = event.getState(); // 连接状态
Watcher.Event.EventType eventType = event.getType(); // 事件类型
String path = event.getPath(); // 受影响的 path
String logPrefix = "【Watcher-" + this.seq.incrementAndGet() + "】";
System.out.println(logPrefix + " 收 到 Watcher 通 知 ");
System.out.println(logPrefix + "连接状态:\t" + keeperState.toString());
System.out.println(logPrefix + "事件类型:\t" + eventType.toString());
if (Event.KeeperState.SyncConnected == keeperState) {
if (Event.EventType.None == eventType) { // 成功连接上 ZK 服务器
System.out.println(logPrefix + "成功连接上 ZK 服务器");
connectedSemaphore.countDown();
} else if (Event.EventType.NodeCreated == eventType) { //创建节点
System.out.println(logPrefix + "节点创建");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.exists(path, true);
} else if (Event.EventType.NodeDataChanged == eventType) { //更新节点
System.out.println(logPrefix + "节点数据更新");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(logPrefix + " 数据内容: " + this.readData(PARENT_PATH, true));
} else if (Event.EventType.NodeChildrenChanged == eventType) { //更新子节点
System.out.println(logPrefix + "子节点变更");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(logPrefix + " 子 节 点 列 表 : " + this.getChildren(PARENT_PATH, true));
} else if (Event.EventType.NodeDeleted == eventType) { //删除节点
System.out.println(logPrefix + "节点 " + path + " 被删除");
}
} else if (Watcher.Event.KeeperState.Disconnected == keeperState) {
System.out.println(logPrefix + "与 ZK 服务器断开连接");
} else if (Watcher.Event.KeeperState.AuthFailed == keeperState) {
System.out.println(logPrefix + "权限检查失败");
} else if (Watcher.Event.KeeperState.Expired == keeperState) {
System.out.println(logPrefix + "会话失效");
}
System.out.println("--------------------------------------------");
}
}
ZK 认证机制
public class TestZookeeperAuth implements Watcher {
final static String CONNECT_ADDR = "192.168.71.128:2181"; // 连接地址
final static String PATH = "/testAuth"; // 测试路径
final static String PATH_DEL = "/testAuth/delNode";
final static String authentication_type = "digest"; // 认证类型
final static String correctAuthentication = "123456"; // 认证正确方法
final static String badAuthentication = "654321"; // 认证错误方法
private static final String LOG_PREFIX_OF_MAIN = "【Main】"; // 标识
static ZooKeeper zk = null;
private final CountDownLatch connectedSemaphore = new CountDownLatch(1); // 设置为1,只需要等待一个线程
AtomicInteger seq = new AtomicInteger(); // 计时器
public static void main(String[] args) throws Exception {
TestZookeeperAuth testAuth = new TestZookeeperAuth();
testAuth.createConnection(CONNECT_ADDR, 2000);
List<ACL> acls = new ArrayList<>(1);
acls.addAll(Ids.CREATOR_ALL_ACL);
try {
zk.create(PATH, "init content".getBytes(), acls, CreateMode.PERSISTENT);
System.out.println("使用授权 key:" + correctAuthentication + "创建节点:" + PATH
+ ", 初始内容是: init content");
} catch (Exception e) {
e.printStackTrace();
}
try {
zk.create(PATH_DEL, "will be deleted! ".getBytes(), acls, CreateMode.PERSISTENT);
System.out.println("使用授权 key:" + correctAuthentication + "创建节点:" + PATH_DEL + ", 初始内容是: init content");
} catch (Exception e) {
e.printStackTrace();
}
// 获取数据
getDataByNoAuthentication();
getDataByBadAuthentication();
getDataByCorrectAuthentication();
// 更新数据
updateDataByNoAuthentication();
updateDataByBadAuthentication();
updateDataByCorrectAuthentication();
// 删除数据
deleteNodeByBadAuthentication();
deleteNodeByNoAuthentication();
deleteNodeByCorrectAuthentication();
Thread.sleep(1000);
deleteParent();
//释放连接
testAuth.releaseConnection();
}
static void getDataByBadAuthentication() { // 获取数据:采用错误的密码
String prefix = "[使用错误的授权信息]";
try {
ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
//授权
badzk.addAuthInfo(authentication_type, badAuthentication.getBytes());
Thread.sleep(2000);
System.out.println(prefix + "获取数据:" + PATH);
System.out.println(prefix + "成功获取数据:" + Arrays.toString(badzk.getData(PATH, false, null)));
} catch (Exception e) {
System.err.println(prefix + "获取数据失败,原因:" + e.getMessage());
}
}
static void getDataByNoAuthentication() { // 获取数据:不采用密码, 没有addAuthInfo()
String prefix = "[不使用任何授权信息]";
try {
System.out.println(prefix + "获取数据:" + PATH);
ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
Thread.sleep(2000);
System.out.println(prefix + "成功获取数据:" + Arrays.toString(nozk.getData(PATH, false, null)));
} catch (Exception e) {
System.err.println(prefix + "获取数据失败,原因:" + e.getMessage());
}
}
static void getDataByCorrectAuthentication() { // 采用正确的密码
String prefix = "[使用正确的授权信息]";
try {
System.out.println(prefix + "获取数据:" + PATH);
System.out.println(prefix + "成功获取数据:" + Arrays.toString(zk.getData(PATH, false, null)));
} catch (Exception e) {
System.out.println(prefix + "获取数据失败,原因:" + e.getMessage());
}
}
static void updateDataByNoAuthentication() { // 更新数据:不采用密码
String prefix = "[不使用任何授权信息]";
System.out.println(prefix + "更新数据: " + PATH);
try {
ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
Thread.sleep(2000);
Stat stat = nozk.exists(PATH, false);
if (stat != null) {
nozk.setData(PATH, prefix.getBytes(), -1);
System.out.println(prefix + "更新成功");
}
} catch (Exception e) {
System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
}
}
static void updateDataByBadAuthentication() { // 更新数据:采用错误的密码
String prefix = "[使用错误的授权信息]";
System.out.println(prefix + "更新数据:" + PATH);
try {
ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
//授权
badzk.addAuthInfo(authentication_type, badAuthentication.getBytes());
Thread.sleep(2000);
Stat stat = badzk.exists(PATH, false);
if (stat != null) {
badzk.setData(PATH, prefix.getBytes(), -1);
System.out.println(prefix + "更新成功");
}
} catch (Exception e) {
System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
}
}
static void updateDataByCorrectAuthentication() { // 更新数据:采用正确的密码
String prefix = "[使用正确的授权信息]";
System.out.println(prefix + "更新数据:" + PATH);
try {
Stat stat = zk.exists(PATH, false);
if (stat != null) {
zk.setData(PATH, prefix.getBytes(), -1);
System.out.println(prefix + "更新成功");
}
} catch (Exception e) {
System.err.println(prefix + "更新失败,原因是:" + e.getMessage());
}
}
static void deleteNodeByNoAuthentication() { // 不使用密码 删除节点
String prefix = "[不使用任何授权信息]";
try {
System.out.println(prefix + " 删 除 节 点 :" + PATH_DEL);
ZooKeeper nozk = new ZooKeeper(CONNECT_ADDR, 2000, null);
Thread.sleep(2000);
Stat stat = nozk.exists(PATH_DEL, false);
if (stat != null) {
nozk.delete(PATH_DEL, -1);
System.out.println(prefix + "删除成功");
}
} catch (Exception e) {
System.err.println(prefix + "删除失败,原因是:" + e.getMessage());
}
}
static void deleteNodeByBadAuthentication() { // 采用错误的密码删除节点
String prefix = "[使用错误的授权信息]";
try {
System.out.println(prefix + " 删 除 节 点 :" + PATH_DEL);
ZooKeeper badzk = new ZooKeeper(CONNECT_ADDR, 2000, null);
//授权
badzk.addAuthInfo(authentication_type, badAuthentication.getBytes());
Thread.sleep(2000);
Stat stat = badzk.exists(PATH_DEL, false);
if (stat != null) {
badzk.delete(PATH_DEL, -1);
System.out.println(prefix + "删除成功");
}
} catch (Exception e) {
System.err.println(prefix + "删除失败,原因是:" + e.getMessage());
}
}
static void deleteNodeByCorrectAuthentication() { // 使用正确的密码删除节点
String prefix = "[使用正确的授权信息]";
try {
System.out.println(prefix + "删除节点:" + PATH_DEL);
Stat stat = zk.exists(PATH_DEL, false);
if (stat != null) {
zk.delete(PATH_DEL, -1);
System.out.println(prefix + "删除成功");
}
} catch (Exception e) {
System.out.println(prefix + "删除失败,原因是:" + e.getMessage());
}
}
static void deleteParent() { // 使用正确的密码删除节点
try {
Stat stat = zk.exists(PATH_DEL, false);
if (stat == null) {
zk.delete(PATH, -1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void process(WatchedEvent event) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (event == null) {
return;
}
Event.KeeperState keeperState = event.getState(); // 连接状态
Event.EventType eventType = event.getType(); // 事件类型
String path = event.getPath(); // 受影响的 path
String logPrefix = "【Watcher-" + this.seq.incrementAndGet() + "】";
System.out.println(logPrefix + " 受影响的 path: " + path);
System.out.println(logPrefix + " 收 到 Watcher 通 知 ");
System.out.println(logPrefix + "连接状态:\t" + keeperState.toString());
System.out.println(logPrefix + "事件类型:\t" + eventType.toString());
if (Event.KeeperState.SyncConnected == keeperState) {
if (Event.EventType.None == eventType) { // 成功连接上 ZK 服务器
System.out.println(logPrefix + "成功连接上 ZK 服务器");
connectedSemaphore.countDown();// 发送连接成功信号
}
} else if (Event.KeeperState.Disconnected == keeperState) {
System.out.println(logPrefix + "与 ZK 服务器断开连接");
} else if (Event.KeeperState.AuthFailed == keeperState) {
System.out.println(logPrefix + "权限检查失败");
} else if (Event.KeeperState.Expired == keeperState) {
System.out.println(logPrefix + "会话失效");
}
System.out.println("--------------------------------------------");
}
public void createConnection(String connectString, int sessionTimeout) { // 创建 ZK 连接
this.releaseConnection();
try {
zk = new ZooKeeper(connectString, sessionTimeout, this);
//添加节点授权
zk.addAuthInfo(authentication_type, correctAuthentication.getBytes()); // digest
System.out.println(LOG_PREFIX_OF_MAIN + "开始连接 ZK 服务器");
connectedSemaphore.await(); //倒数等待
} catch (Exception e) {
e.printStackTrace();
}
}
public void releaseConnection() { // 关闭 ZK 连接
if (zk != null) {
try {
zk.close();
} catch (InterruptedException ignored) {
}
}
}
}
zkClient
基本操作
public class ZkClientOperator {
static final String CONNECT_ADDR = "192.168.71.128:2181"; // zookeeper 地址
static final int SESSION_OUTTIME = 10000; // session 超时时间 ms
public static void main(String[] args) throws Exception {
// ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), SESSION_OUTTIME);
ZkClient zkc = new ZkClient(CONNECT_ADDR, SESSION_OUTTIME);
//1. create and delete 方法
zkc.createEphemeral("/temp");
zkc.createPersistent("/super/c1", true);
Thread.sleep(10000);
zkc.delete("/temp");
zkc.deleteRecursive("/super");
//2. 设置 path 和 data 并且读取子节点和每个节点的内容
zkc.createPersistent("/super", "1234");
zkc.createPersistent("/super/c1", "c1 内 容 ");
zkc.createPersistent("/super/c2", "c2 内容");
List<String> list = zkc.getChildren("/super");
for (String p : list) {
System.out.println(p);
String rp = "/super/" + p;
String data = zkc.readData(rp);
System.out.println("节点为:" + rp + ",内容为: " + data);
}
//3. 更新和判断节点是否存在zkc.writeData("/super/c1", " 新 内 容 ");
System.out.println(zkc.readData("/super/c1").toString());
System.out.println(zkc.exists("/super/c1"));
// 4.递归删除/super 内容
zkc.deleteRecursive("/super");
}
}
发现代码比原生方法少了好多
监听机制
public class TestZkClientWatcher {
/**
* zookeeper 地址
*/
static final String CONNECT_ADDR = "192.168.71.128:2181";
/**
* session 超时时间
*/
static final int SESSION_OUTTIME = 10000;//ms
@Test
public void testZkClientWatcher1() throws Exception { // subscribeChildChanges 方法 订阅子节点变化
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), SESSION_OUTTIME);
//对父节点添加监听子节点变化。
zkc.subscribeChildChanges("/super", new IZkChildListener() {
@Override
public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
System.out.println("parentPath: " + parentPath);
System.out.println("currentChilds: " + currentChilds);
}
});
Thread.sleep(3000);
zkc.createPersistent("/super");
Thread.sleep(1000);
zkc.createPersistent("/super" + "/" + "c1", "c1 内容");
Thread.sleep(1000);
zkc.createPersistent("/super" + "/" + "c2", "c2 内容");
Thread.sleep(1000);
zkc.delete("/super/c2");
Thread.sleep(1000);
zkc.deleteRecursive("/super");
Thread.sleep(Integer.MAX_VALUE);
}
@Test
public void testZkClientWatcher2() throws Exception { // subscribeDataChanges 订阅内容变化
ZkClient zkc = new ZkClient(new ZkConnection(CONNECT_ADDR), SESSION_OUTTIME);
zkc.createPersistent("/super", "1234");
//对父节点添加监听子节点变化。
zkc.subscribeDataChanges("/super", new IZkDataListener() {
@Override
public void handleDataDeleted(String path) throws Exception {
System.out.println("删除的节点为:" + path);
}
@Override
public void handleDataChange(String path, Object data) throws Exception {
System.out.println("变更的节点为:" + path + ", 变更内容为:" + data);
}
});
Thread.sleep(3000);
zkc.writeData("/super", "456", -1);
Thread.sleep(1000);
zkc.delete("/super");
Thread.sleep(Integer.MAX_VALUE);
}
}
Curator
基本操作
添加事务依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-test</artifactId>
<version>2.12.0</version>
</dependency>
<!-- 注意需要注释掉原生的zookeeper依赖 -->
<!-- <dependency>-->
<!-- <groupId>org.apache.zookeeper</groupId>-->
<!-- <artifactId>zookeeper</artifactId>-->
<!-- <version>3.4.6</version>-->
<!-- </dependency>-->
public class OperatorTest {
//ZooKeeper 服务地址
private static final String SERVER = "192.168.71.128:2181";
//会话超时时间
private final int SESSION_TIMEOUT = 30000;
//连接超时时间
private final int CONNECTION_TIMEOUT = 5000;
/*
* baseSleepTimeMs:初始的重试等待时间 maxRetries:最多重试次数
* ExponentialBackoffRetry:重试一定次数,每次重试时间依次递增 RetryNTimes:
* 重试 N 次 RetryOneTime:重试一次 RetryUntilElapsed:重试一定时间
*/
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
//创建连接实例
private CuratorFramework curatorFramework = null;
@org.junit.Before
public void init() {
//创建 CuratorFrameworkImpl 实例
curatorFramework = CuratorFrameworkFactory.newClient(SERVER, SESSION_TIMEOUT, CONNECTION_TIMEOUT, retryPolicy);
//启动
curatorFramework.start();
}
@Test
public void testCreate() throws Exception { // 测试创建节点
//创建永久节点
curatorFramework.create().forPath("/curator", "/curator data".getBytes());
//创建永久有序节点
curatorFramework.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL)
.forPath("/curator_sequential", "/curator_sequential data".getBytes());
//创建临时节点
curatorFramework.create().withMode(CreateMode.EPHEMERAL)
.forPath("/curator/ephemeral", "/curator/ephemeral data".getBytes());
//创建临时有序节点
curatorFramework.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
.forPath("/curator/ephemeral_path1", "/curator/ephemeral_path1 data".getBytes());
}
@Test
public void testCheck() throws Exception { // 测试检查某个节点是否存在
Stat stat1 = curatorFramework.checkExists().forPath("/curator");
Stat stat2 = curatorFramework.checkExists().forPath("/curator2");
System.out.println("'/curator'是否存在: " + (stat1 != null));
System.out.println("'/curator2'是否存在: " + (stat2 != null));
}
@Test
public void testSetDataAsync() throws Exception { // 测试异步设置节点数据
//创建监听器
CuratorListener listener = (client, event) -> System.out.println(event.getPath());
//添加监听器
curatorFramework.getCuratorListenable().addListener(listener);
//异步设置某个节点数据
curatorFramework.setData().inBackground().forPath("/curator", "sync".getBytes());
//为了防止单元测试结束从而看不到异步执行结果,因此暂停 10 秒
Thread.sleep(10000);
}
@Test
public void testSetDataAsyncWithCallback() throws Exception { // 测试另一种异步执行获取通知的方式
BackgroundCallback callback = (client, event) -> System.out.println(event.getPath());
//异步设置某个节点数据
curatorFramework.setData().inBackground(callback).forPath("/curator", "/curator modified data with Callback ".getBytes());
//为了防止单元测试结束从而看不到异步执行结果,因此暂停 10 秒
Thread.sleep(10000);
}
@Test
public void testDelete() throws Exception { // 测试删除节点
//创建测试节点
curatorFramework.create().orSetData().creatingParentsIfNeeded()
.forPath("/curator/del_key1", "/curator/del_key1 data".getBytes());
curatorFramework.create().orSetData().creatingParentsIfNeeded()
.forPath("/curator/del_key2", "/curator/del_key2 data".getBytes());
curatorFramework.create().forPath("/curator/del_key2/test_key", "test_key data".getBytes());
//删除该节点
curatorFramework.delete().forPath("/curator/del_key1");
//级联删除子节点
curatorFramework.delete().guaranteed().deletingChildrenIfNeeded().forPath("/curator/del_key2");
}
@Test
public void testTransaction() throws Exception { // 测试事务管理:碰到异常,事务会回滚
//定义几个基本操作
CuratorOp createOp = curatorFramework.transactionOp().create()
.forPath("/curator/one_path", "some data".getBytes());
CuratorOp setDataOp = curatorFramework.transactionOp().setData()
.forPath("/curator", "other data".getBytes());
CuratorOp deleteOp = curatorFramework.transactionOp().delete()
.forPath("/curator");
//事务执行结果
List<CuratorTransactionResult> results = curatorFramework.transaction()
.forOperations(createOp, setDataOp, deleteOp);
//遍历输出结果
for (CuratorTransactionResult result : results) {
System.out.println("执行结果是: " + result.getForPath() + "--" + result.getType());
}
}
}
监听机制
public class EventTest {
//ZooKeeper 服务地址
private static final String SERVER = "192.168.71.128:2181";
//会话超时时间
private final int SESSION_TIMEOUT = 30000;
//连接超时时间
private final int CONNECTION_TIMEOUT = 5000;
/*
* baseSleepTimeMs:初始的重试等待时间
* maxRetries:最多重试次数
* ExponentialBackoffRetry:重试一定次数,每次重试时间依次递增
* RetryNTimes:重试 N 次
* RetryOneTime:重试一次
* RetryUntilElapsed:重试一定时间
*/
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
//创建连接实例
private CuratorFramework client = null;
@org.junit.Before
public void init() {
//创建 CuratorFrameworkImpl 实例
client = CuratorFrameworkFactory.newClient(SERVER, SESSION_TIMEOUT, CONNECTION_TIMEOUT, retryPolicy);
//启动
client.start();
}
@Test
public void TestListenterOne() throws Exception { // 对指定的节点进行添加操作 仅仅能监控指定的本节点的数据修改,删除 操作 并且只能监听一次 --->不好
client.create().orSetData().withMode(CreateMode.PERSISTENT).forPath("/test", "test".getBytes());
// 注册观察者,当节点变动时触发
byte[] data = client.getData().usingWatcher(new Watcher() {
@Override
public void process(WatchedEvent event) {
System.out.println("获取 test 节点 监听器 : " + event);
}
}).forPath("/test");
client.create().orSetData().withMode(CreateMode.PERSISTENT).forPath("/test", "test".getBytes());
Thread.sleep(1000);
client.create().orSetData().withMode(CreateMode.PERSISTENT).forPath("/test", "test".getBytes());
Thread.sleep(1000);
System.out.println("节点数据: " + new String(data));
Thread.sleep(10000);
}
/**
* @描述:第二种监听器的添加方式: Cache 的三种实现 Path Cache:监视一个路径下 1)孩子结点的创建、2)删除,3)以及结点数据的更新。 产生的事件会传递给注册的 PathChildrenCacheListener。 Node
* Cache:监视一个结点的创建、更新、删除,并将结点的数据缓存在本地。 Tree Cache:Path Cache 和 Node Cache 的“合体”,监视路径下的创建、更新、删除事件,并缓存路径下所有孩子结点的数据。
*/
//1.path Cache 连接 路径 是否获取数据
//能监听所有的字节点 且是无限监听的模式 但是 指定目录下节点的子节点不再监听
@Test
public void setListenterTwoOne() throws Exception {
ExecutorService pool = Executors.newCachedThreadPool();
PathChildrenCache childrenCache = new PathChildrenCache(client, "/test", true);
PathChildrenCacheListener childrenCacheListener = (client, event) -> {
System.out.println("开始进行事件分析:-----");
ChildData data = event.getData();
switch (event.getType()) {
case CHILD_ADDED:
System.out.println("CHILD_ADDED : " + data.getPath() + " 数据:" + Arrays.toString(data.getData()));
System.out.println("开始进行事件分析:-----");
break;
case CHILD_REMOVED:
System.out.println("CHILD_REMOVED : " + data.getPath() + " 数据:" + Arrays.toString(data.getData()));
break;
case CHILD_UPDATED:
System.out.println("CHILD_UPDATED : " + data.getPath() + " 数据:" + Arrays.toString(data.getData()));
break;
case INITIALIZED:
System.out.println("CHILD_INITIALIZED : " + data.getPath() + " 数据:" + Arrays.toString(data.getData()));
break;
default:
break;
}
};
childrenCache.getListenable().addListener(childrenCacheListener);
System.out.println("Register zk watcher successfully!");
childrenCache.start(StartMode.POST_INITIALIZED_EVENT);
//创建一个节点
client.create().orSetData().withMode(CreateMode.PERSISTENT).forPath("/test", "test".getBytes());
client.create().orSetData().withMode(CreateMode.EPHEMERAL).forPath("/test/node01", "enjoy".getBytes());
Thread.sleep(1000);
client.create().orSetData().withMode(CreateMode.EPHEMERAL).forPath("/test/node02", "deer".getBytes());
Thread.sleep(1000);
client.create().orSetData().withMode(CreateMode.EPHEMERAL).forPath("/test/node02", "demo".getBytes());
Thread.sleep(1000);
client.delete().forPath("/test/node02");
Thread.sleep(10000);
}
//2.Node Cache 监控本节点的变化情况 连接 目录 是否压缩
//监听本节点的变化 节点可以进行修改操作 删除节点后会再次创建(空节点)
@Test
public void setListenterTwoTwo() throws Exception {
ExecutorService pool = Executors.newCachedThreadPool();
//设置节点的 cache
final NodeCache nodeCache = new NodeCache(client, "/test", false);
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("the test node is change and result is :");
System.out.println("path : " + nodeCache.getCurrentData().getPath());
System.out.println("data : " + new
String(nodeCache.getCurrentData().getData()));
System.out.println("stat : " + nodeCache.getCurrentData().getStat());
}
});
nodeCache.start();
client.create().orSetData().withMode(CreateMode.PERSISTENT).forPath("/test", "test".getBytes());
Thread.sleep(1000);
client.create().orSetData().withMode(CreateMode.PERSISTENT).forPath("/test", "enjoy".getBytes()
);
Thread.sleep(10000);
}
//3.Tree Cache
// 监控 指定节点和节点下的所有的节点的变化--无限监听 可以进行本节点的删除(不在创建)
@Test
public void TestListenterTwoThree() throws Exception {
ExecutorService pool = Executors.newCachedThreadPool();
//设置节点的 cache
TreeCache treeCache = new TreeCache(client, "/test");
//设置监听器和处理过程
treeCache.getListenable().addListener((client, event) -> {
ChildData data = event.getData();
if (data != null) {
switch (event.getType()) {
case NODE_ADDED:
System.out.println("NODE_ADDED : " + data.getPath() + " 数据:" + new String(data.getData()));
break;
case NODE_REMOVED:
System.out.println("NODE_REMOVED : " + data.getPath() + "数据:" + new String(data.getData()));
break;
case NODE_UPDATED:
System.out.println("NODE_UPDATED : " + data.getPath() + "数据:" + new String(data.getData()));
break;
default:
break;
}
} else {
System.out.println("data is null : " + event.getType());
}
});
//开始监听
treeCache.start();
//创建一个节点
client.create().orSetData().withMode(CreateMode.PERSISTENT).forPath("/test", "test".getBytes());
Thread.sleep(1000);
client.create().orSetData().withMode(CreateMode.EPHEMERAL).forPath("/test/node01", "enjoy".getBytes());
Thread.sleep(1000);
client.create().orSetData().withMode(CreateMode.EPHEMERAL).forPath("/test/node01", "deer".getBytes());
Thread.sleep(1000);
client.create().orSetData().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL)
.forPath("/test/node02/node02_2", "deer".getBytes());
Thread.sleep(10000);
}
}