上篇文章介绍了Curator中的分布式计数器及其原理,本篇文章会对Curator下的监听机制。Zookeeper原生支持对节点事件进行监听,Curator也封装了原生的操作,下来先来看下基于
org.apache.zookeeper.Watcher
的原生监听方式
原生监听-usingWatcher
先看下org.apache.curator.framework.CuratorFramework#getData
方法的返回值GetDataBuilder
的构造
public interface GetDataBuilder extends
Watchable<BackgroundPathable<byte[]>>,//事件监听
BackgroundPathable<byte[]>,//异步操作
Statable<WatchPathable<byte[]>>,//节点属性存储相关
Decompressible<GetDataWatchBackgroundStatable>//数据压缩
{
}
其中org.apache.curator.framework.api.Watchable接口中方法如下
public interface Watchable<T>
{
public T watched();
//设置监听器
public T usingWatcher(Watcher watcher);
public T usingWatcher(CuratorWatcher watcher);
}
我们可以使用usingWatcher()
方法来新增一个节点的监听器
具体使用案例如下
public class Watcher {
public static void main(String[] args) throws Exception {
CuratorFramework zkClient = getZkClient();
String path = "/watchNode";
byte[] initData = "initData".getBytes();
//先创建一个用于事件监听的测试节点
zkClient.create().forPath(path, initData);
//设置监听器
zkClient.getData().usingWatcher(new org.apache.zookeeper.Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("监听到节点事件:" + JSON.toJSONString(watchedEvent));
}
}).forPath(path);
//第一次更新
zkClient.setData().forPath(path, "1".getBytes());
//第二次更新
zkClient.setData().forPath(path, "2".getBytes());
//Sleep等待监听事件触发
Thread.sleep(Integer.MAX_VALUE);
}
private static CuratorFramework getZkClient() {
String zkServerAddress = "127.0.0.1:2182,127.0.0.1:2183,127.0.0.1:2184";
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(1000, 3, 5000);
CuratorFramework zkClient = CuratorFrameworkFactory.builder()
.connectString(zkServerAddress)
.sessionTimeoutMs(5000)
.connectionTimeoutMs(5000)
.retryPolicy(retryPolicy)
.build();
zkClient.start();
return zkClient;
}
}
在命令行出输出结果如下
可以看到,代码中进行了两次修改,监听事件却只触发了一次,类型为NodeDataChanged,这也是原生监听事件的不足,即原生Watch事件只能触发一次
Curator-Cache
为了免去开发人员重复注册Watcher的麻烦,org.apache.curator.framework.recipes.cache
下提供了对监听监听事件的高级封装,主要类有以下三个
类名 | 用途 |
---|---|
NodeCache | 监听节点对应增、删、改操作 |
PathChildrenCache | 监听节点下一级子节点的增、删、改操作 |
TreeCache | 可以将指定的路径节点作为根节点,对其所有的子节点操作进行监听,呈现树形目录的监听 |
下面分别介绍用法,NodeCache由于其实现较为简单,也会分析下原理
NodeCache
先看下用法
public class Watcher {
public static void main(String[] args) throws Exception {
CuratorFramework zkClient = getZkClient();
String path = "/nodeCache";
byte[] initData = "initData".getBytes();
//创建节点用于测试
zkClient.create().forPath(path, initData);
NodeCache nodeCache = new NodeCache(zkClient, path);
//调用start方法开始监听
nodeCache.start();
//添加NodeCacheListener监听器
nodeCache.getListenable().addListener(new NodeCacheListener() {
@