In the Zookeeper client (4)-Curator , we introduced the node operation of the Curator client, as well as asynchronous operations and transaction operations, but we did not introduce how to monitor node changes in Curator, similar to ZkClient. It also provides us with a listener. Cache is a package for event monitoring in curator. The monitoring of events can be viewed as a comparison process between the local cache view and the remote zookeeper view.
- NodeCache: Node cache is used to handle changes in the node itself, callback interface NodeCacheListener
- PathChildrenCache: The child node cache is used to handle the child node changes of the node, and the callback interface PathChildrenCacheListener
- TreeCache: The combination of NodeCache and PathChildrenCache, callback interface TreeCacheListener
NodeCache
First of all, let ’s take a look at NodeCache. We follow the steps of Curator to Zookeeper introduced last time. First, we will first connect to Zookeeper. Then we add a listener as follows:
public class CuratorTest {
private static final String CONNENT_ADDR = "192.168.80.130:2181";
public static void main(String[] args) throws Exception {
CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
.connectString(CONNENT_ADDR)
.connectionTimeoutMs(5000) //连接超时时间
.sessionTimeoutMs(5000) //会话超时时间
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
curatorFramework.start();
final NodeCache cache = new NodeCache(curatorFramework, "/node1", false);
cache.start(); //需要调用nodeCache的start方法能进行缓存和事件监听
cache.getListenable().addListener(new NodeCacheListener() {
//监听节点变化
@Override
public void nodeChanged() throws Exception {
System.out.println("路径为:" + cache.getCurrentData().getPath());
System.out.println("数据为:" + new String(cache.getCurrentData().getData()));
System.out.println("状态为:" + cache.getCurrentData().getStat());
}
});
curatorFramework.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.forPath("/node1", "value".getBytes());
Thread.sleep(1000);
}
}
The first parameter is the frame client passed into the created Curator, the second parameter is the path of the listening node, and the third overload parameter dataIsCompressed indicates whether to compress the data. Finally, you must call the start method of NodeCache to perform caching and event monitoring.
Here we find that if the node monitored by NodeCache is empty (that is, the incoming path does not exist). Then if we create the corresponding node later, it will also trigger an event to call back the nodeChanged method.
In addition, the event monitoring method cache.start () of the startup node can also pass parameters, which defaults to false, as follows
void start (boolean buildInitial) // true means to cache the current node
The only parameter, buildInitial, represents whether to cache the node's data immediately. If it is set to true, you can get the information of the corresponding node ChildData class by calling the GetCurrentData method of NodeCache immediately when start is started. If it is set to false, you cannot get the corresponding information.
When testing false as above, try to add a sleep time in the front, otherwise you may not get the expected results, because the interval may be too short and only trigger an event.
PathChildrenCache
After understanding the changes of Curator listening nodes, let's take a look at how Curator listens for the addition, modification and deletion of child nodes
public class CuratorTest {
private static final String CONNENT_ADDR = "192.168.80.130:2181";
public static void main(String[] args) throws Exception {
CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
.connectString(CONNENT_ADDR)
.connectionTimeoutMs(5000) //连接超时时间
.sessionTimeoutMs(5000) //会话超时时间
.retryPolicy(new ExponentialBackoffRetry(1000, 3))
.build();
curatorFramework.start();
final PathChildrenCache cache = new PathChildrenCache(curatorFramework, "/node1", true);
cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);//只有POST_INITIALIZED_EVENT模式才会启用监听功能
cache.getListenable().addListener(new PathChildrenCacheListener() {
//监听子节点的变化
@Override
public void childEvent(CuratorFramework cf, PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
case CHILD_ADDED: //新增
System.out.println("新增子节点路径:" + event.getData().getPath());
System.out.println("新增子节点数据:" + new String(event.getData().getData()));
break;
case CHILD_UPDATED: //更新
System.out.println("更新子节点路径:" + event.getData().getPath());
System.out.println("更新子节点数据:" + new String(event.getData().getData()));
break;
case CHILD_REMOVED: //移除
System.out.println("移除子节点路径:" + event.getData().getPath());
System.out.println("移除子节点数据:" + new String(event.getData().getData()));
break;
default:
break;
}
}
});
curatorFramework.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.forPath("/node1/n1", "v1".getBytes());
Thread.sleep(2000);
}
}
Here we pay a little attention, that is the third parameter cacheData in the figure below, which is different from the NodeCache we introduced above. Here it indicates whether to cache the node content. If cacheData is true, then the node content will be obtained at the same time when the node list change event is received.
In addition, after creating an instance of PathChildrenCacheListener, you need to register this instance to the PathChildrenCache cache instance and use the addListener method of the cache instance. Then use the start method of the cache instance nodeCache to start the event monitoring of the node.
The start method here needs to pass in the starting mode. Three modes can be introduced:
-
NORMAL: When the asynchronous initialization cache is
started, the cache is initialized asynchronously, and no notification will be issued after completion. -
BUILD_INITIAL_CACHE: When the synchronous initialization cache
starts, the synchronous initialization cache, and after creating the cache, pull the corresponding data from the server. -
POST_INITIALIZED_EVENT: Initialize the cache asynchronously and trigger the completion event. At
startup, asynchronously initialize the cache. The initialization completion triggers the PathChildrenCacheEvent.Type # INITIALIZED event. The Listener in the cache will receive a notification of the event.
In addition, PathChildrenCache monitors the addition, modification, and deletion of child nodes. It is basically similar to ZkClient.
- Can only listen to child nodes, not the current node
- Can't listen recursively, the child nodes under the child node can't monitor recursively
But there is a slight difference here. In ZkClient, we are operating the child node under the child node, our listener will not have any trigger events, but in Curator we are operating the child node under the child node, the listener It will be felt, but it can not get the information of the child nodes under the child node, as follows:
TreeCache
Above we know that NodeCache is used to observe the ZNode itself. If the ZNode node itself is created, updated or deleted, then the Node Cache will update the cache and trigger an event to the registered listener. The interface corresponding to the listener is NodeCacheListener.
PathChildrenCache child node cache is used to observe the child nodes of ZNode and cache the state of child nodes. If the child nodes of ZNode are created, updated or deleted, then PathChildrenCache will update the cache and trigger an event to the registered listener. The interface is PathChildrenCacheListener.
TreeCache can be seen as a combination of the above two. TreeCache observes all the data of the current ZNode node. TreeCache can not only monitor child nodes, but also the node itself.
Its usage is basically similar to PathChildrenCache, except that it corresponds to the addition, modification, and deletion of nodes. The method name of the event type of TreeCache is different.