1、Zookeeper API
1.1、描述
在 ZooKeeper 中,Watcher 是一次性的,不会自动重新注册。因此,如果你希望在特定事件(如节点数据变化)发生后继续监听其他事件(如节点删除),你需要在每次事件触发时重新注册 Watcher
1.2、示例
首先,确保你在项目中添加了 Zookeeper 的依赖:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.3</version>
</dependency>
完整示例代码
import org.apache.zookeeper.*;
import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.AsyncCallback.StringCallback;
import org.apache.zookeeper.data.Stat;
import java.io.IOException;
public class ZooKeeperExample {
private static ZooKeeper zk;
private static final String ZK_SERVER = "localhost:2181";
private static final int SESSION_TIMEOUT = 3000;
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
// 创建 ZooKeeper 客户端
zk = new ZooKeeper(ZK_SERVER, SESSION_TIMEOUT, new MyWatcher());
// 创建节点
zk.create("/example", "data".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, new MyStringCallback(), null);
// 检查节点状态并设置 Watcher
zk.exists("/example", true, new MyStatCallback(), null);
// 触发节点变化事件
zk.setData("/example", "newData".getBytes(), -1);
// 删除节点,验证 Watcher 是否会监听删除事件
Thread.sleep(2000);
zk.delete("/example", -1);
// 保持程序运行以观察回调
Thread.sleep(10000);
// 关闭 ZooKeeper 客户端
zk.close();
}
// Watcher 实现类
static class MyWatcher implements Watcher {
@Override
public void process(WatchedEvent event) {
System.out.println("Watcher received event: " + event);
try {
if (event.getType() == Event.EventType.NodeDataChanged || event.getType() == Event.EventType.NodeDeleted) {
// 重新设置 Watcher
zk.exists(event.getPath(), true);
}
} catch (KeeperException | InterruptedException e) {
e.printStackTrace();
}
}
}
// StatCallback 实现类
static class MyStatCallback implements StatCallback {
@Override
public void processResult(int rc, String path, Object ctx, Stat stat) {
if (rc == 0) {
System.out.println("Node exists: " + path + ", stat: " + stat);
} else {
System.out.println("Node does not exist: " + path);
}
}
}
// StringCallback 实现类
static class MyStringCallback implements StringCallback {
@Override
public void processResult(int rc, String path, Object ctx, String name) {
if (rc == 0) {
System.out.println("Node created: " + name);
} else {
System.out.println("Node creation failed: " + KeeperException.Code.get(rc));
}
}
}
}
1.3、结果验证
- 首次触发 Watcher:当第一次修改节点数据时,Watcher 会触发并打印事件信息。
- 删除节点:删除节点时,Watcher 会再次触发并打印事件信息,因为在 process 方法中重新注册了 Watcher。
通过这个完整的示例代码,你可以验证 Watcher 是一次性的,并且需要在每次触发后重新注册以继续监听其他事件,包括节点删除事件
2、Apache Curator
2.1、描述
Apache Curator 是一个用于简化 ZooKeeper 客户端开发的 Java 库。它提供了更高层次的 API 来处理 ZooKeeper 的常见任务,例如连接管理、会话管理、重试机制等。以下是一个完整的实例,演示了如何使用 Curator 库来进行回调和监听节点事件
2.2、示例
确保在你的项目中添加了 Curator 的依赖:
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.2.0</version>
</dependency>
完整示例代码
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
public class TreeCacheExample {
private static final String ZK_SERVER = "localhost:2181";
private static final String ZNODE_PATH = "/example";
public static void main(String[] args) throws Exception {
// 创建 Curator 客户端
CuratorFramework client = CuratorFrameworkFactory.newClient(ZK_SERVER, new ExponentialBackoffRetry(1000, 3));
client.start();
client.getConnectionStateListenable().addListener(new ConnectionStateListener() {
@Override
public void stateChanged(CuratorFramework curatorFramework, ConnectionState newState) {
switch (newState) {
case CONNECTED:
System.out.println("Registry connected");
break;
case LOST:
System.out.println("Registry disconnected");
break;
case RECONNECTED:
System.out.println("Registry reconnected");
break;
case SUSPENDED:
System.out.println("Registry suspended");
break;
default:
break;
}
}
});
// 创建 TreeCache
TreeCache treeCache = new TreeCache(client, ZNODE_PATH);
// 添加 TreeCache 监听器
TreeCacheListener listener = new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
switch (event.getType()) {
case NODE_ADDED:
System.out.println("Node added: " + event.getData().getPath());
break;
case NODE_UPDATED:
System.out.println("Node updated: " + event.getData().getPath());
break;
case NODE_REMOVED:
System.out.println("Node removed: " + event.getData().getPath());
break;
default:
break;
}
}
};
treeCache.getListenable().addListener(listener);
// 启动 TreeCache
treeCache.start();
// 进行一些节点操作以触发事件
client.create().forPath(ZNODE_PATH + "/child", "data".getBytes());
client.setData().forPath(ZNODE_PATH + "/child", "newData".getBytes());
client.delete().forPath(ZNODE_PATH + "/child");
// 保持程序运行以观察回调
Thread.sleep(10000);
// 关闭 TreeCache 和 Curator 客户端
treeCache.close();
client.close();
}
}
2.3、结果验证
- ConnectionStateListener 监听Zookeeper的链接状态
- TreeCacheListener 监听Zookeeper 路径的事件
3、对比
TreeCache 和 Watcher 是 Apache Curator 框架和 Apache ZooKeeper 中的两种不同的监听机制,用于监视 ZooKeeper 集群中的节点变化。它们的注册和使用方式有所不同,原因主要在于它们的设计目的和工作机制
Watcher
- 作用: Watcher 是 ZooKeeper 提供的一种机制,用于监视节点的变化。每次客户端对 ZooKeeper 进行读取操作时,可以附带一个 Watcher,当该节点发生变化时,ZooKeeper 会通知客户端。
- 多次注册: Watcher 是一次性的,即每次触发后就失效了。如果客户端需要继续监听该节点的变化,则需要重新注册 Watcher。因此,Watcher 的设计是为了轻量级、精细粒度的监听。
TreeCache
- 作用: TreeCache 是 Apache Curator 提供的一个高级缓存机制,用于监视一个节点及其子节点的变化。它不仅仅是监视单个节点,而是监视整个子树的变化,并将数据缓存在本地。
- 一次注册: TreeCache 通过一次注册,可以持续监视整个子树的变化,并保持缓存的更新。这是因为 TreeCache 维护了一个本地缓存,能够自动处理 ZooKeeper 的事件通知,保持缓存数据的一致性。它通过内部的机制,自动重新注册 Watcher,以保证对子树的变化持续监控。因此,用户不需要手动多次注册
为什么 TreeCache 不像 Watcher 一样多次注册?
1. 设计目的: TreeCache 的设计目的是为了方便地监视和缓存整个子树的变化,提供一个高效、易用的接口来处理复杂的节点监控需求。而 Watcher 是为了提供一个更底层的、精细粒度的节点监控机制,适合一些简单、轻量级的使用场景。
2. 内部实现: TreeCache 内部会自动管理 Watcher 的注册和事件处理,因此用户不需要手动多次注册 Watcher。而 Watcher 需要用户手动管理和重新注册,以确保对节点的持续监控。
3. 使用场景: 对于需要监控多个节点或整个子树变化的场景,TreeCache 提供了更高效和便捷的解决方案,而不需要用户频繁注册 Watcher。
总结来说,TreeCache 和 Watcher 是为了满足不同需求而设计的。TreeCache 通过一次注册,自动管理对节点及子节点的持续监控和缓存更新,而 Watcher 需要用户手动多次注册以实现持续监控
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。