Zookeeper开源客户端Curator之事件监听详解
Curator对Zookeeper典型场景之事件监听进行封装,提供了使用参考。这篇博文笔者带领大家了解一下Curator的实现方式。
引入依赖
对于Curator封装Zookeeper的典型场景使用都放在了recipes中。因此,使用之前需先引入此依赖。
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
以下实例默认节点“/p1”已经被创建切存在于Zookeeper服务器上的。
监听方式一
利用Watcher来对节点进行监听操作,但此监听操作只能监听一次,与原生API并无太大差异。如有典型业务场景需要使用可考虑,但一般情况不推荐使用。下面是具体的使用案例。
package com.secbro.learn.curator; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher; /**
* Created by zhuzs on 2017/4/14.
*/
public class CuratorListenerTest1{
public static void main(String[] args) {
CuratorFramework client = getClient();
String path = "/p1"; try {
byte[] content = client.getData().usingWatcher(new Watcher() {
@Override
public void process(WatchedEvent watchedEvent) {
System.out.println("监听器watchedEvent:" + watchedEvent);
}
}).forPath(path); System.out.println("监听节点内容:" + new String(content)); // 第一次变更节点数据
client.setData().forPath(path,"new content".getBytes()); // 第二次变更节点数据
client.setData().forPath(path,"second content".getBytes()); Thread.sleep(Integer.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
client.close();
} finally {
client.close();
} } private static CuratorFramework getClient(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.0:2181")
.retryPolicy(retryPolicy)
.sessionTimeoutMs(6000)
.connectionTimeoutMs(3000)
.namespace("demo")
.build();
client.start();
return client;
}
}
执行结果:
监听节点内容:new content
监听器watchedEvent:WatchedEvent state:SyncConnected type:NodeDataChanged path:/p1
执行此程序之后,首先会对节点/p1注册一个Watcher监听事件,同时返回当前节点的内容信息。随后改变节点内容为“new content”,此时触发监听事件,并打印出监听事件信息。但当第二次改变节点内容时,监听已经失效,无法再次获得节点变动事件。
方法二
CuratorListener监听,此监听主要针对background通知和错误通知。使用此监听器之后,调用inBackground方法会异步获得监听,而对于节点的创建或修改则不会触发监听事件。具体实例代码如下
package com.secbro.learn.curator; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.api.CuratorListener;
import org.apache.curator.retry.ExponentialBackoffRetry; /**
* Created by zhuzs on 2017/4/14.
*/
public class CuratorListenerTest1 {
public static void main(String[] args) {
CuratorFramework client = getClient();
String path = "/p1"; try {
CuratorListener listener = new CuratorListener() {
@Override
public void eventReceived(CuratorFramework client, CuratorEvent event) throws Exception {
System.out.println("监听事件触发,event内容为:" + event);
}
};
client.getCuratorListenable().addListener(listener);
// 异步获取节点数据
client.getData().inBackground().forPath(path);
// 变更节点内容
client.setData().forPath(path,"123".getBytes()); Thread.sleep(Integer.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
client.close();
} finally {
client.close();
} } private static CuratorFramework getClient(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181")
.retryPolicy(retryPolicy)
.sessionTimeoutMs(6000)
.connectionTimeoutMs(3000)
.namespace("demo")
.build();
client.start();
return client;
}
}
执行结果为:
监听事件触发,event内容为:CuratorEventImpl{type=WATCHED, resultCode=3, path='null', name='null', children=null, context=null, stat=null, data=null, watchedEvent=WatchedEvent state:SyncConnected type:None path:null, aclList=null}
监听事件触发,event内容为:CuratorEventImpl{type=GET_DATA, resultCode=0, path='/p1', name='null', children=null, context=null, stat=17814,18054,1491458317592,1492218568138,12,0,0,0,3,0,17814
, data=[49, 50, 51], watchedEvent=null, aclList=null}
其中两次触发监听事件,第一次触发为注册监听事件时触发,第二次为getData异步处理返回结果时触发。而setData的方法并未触发监听事件。
方法三
Curator引入了Cache来实现对Zookeeper服务端事件监听,Cache事件监听可以理解为一个本地缓存视图与远程Zookeeper视图的对比过程。Cache提供了反复注册的功能。Cache分为两类注册类型:节点监听和子节点监听。
NodeCache
用于监听数据节点本身的变化。提供了两个构造方法:
public NodeCache(CuratorFramework client, String path) public NodeCache(CuratorFramework client, String path, boolean dataIsCompressed)
其中参数dataIsCompressed表示是否对数据进行压缩,而第一个方法内部实现为调用第二个方法,且dataIsCompressed默认设为false。
对节点的监听需要配合回调函数来进行处理接收到监听事件之后的业务处理。NodeCache通过NodeCacheListener来完成后续处理。具体代码示例如下:
package com.secbro.learn.curator; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry; /**
* Created by zhuzs on 2017/4/15.
*/
public class CuratorNodeCacheTest { public static void main(String[] args) throws Exception { CuratorFramework client = getClient();
String path = "/p1";
final NodeCache nodeCache = new NodeCache(client,path);
nodeCache.start();
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("监听事件触发");
System.out.println("重新获得节点内容为:" + new String(nodeCache.getCurrentData().getData()));
}
});
client.setData().forPath(path,"456".getBytes());
client.setData().forPath(path,"789".getBytes());
client.setData().forPath(path,"123".getBytes());
client.setData().forPath(path,"222".getBytes());
client.setData().forPath(path,"333".getBytes());
client.setData().forPath(path,"444".getBytes());
Thread.sleep(15000); } private static CuratorFramework getClient(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181")
.retryPolicy(retryPolicy)
.sessionTimeoutMs(6000)
.connectionTimeoutMs(3000)
.namespace("demo")
.build();
client.start();
return client;
}
}
执行结果:
监听事件触发
重新获得节点内容为:123
监听事件触发
重新获得节点内容为:333
监听事件触发
重新获得节点内容为:444
NodeCache的start方法有一个带Boolean参数的方法,如果设置为true则在首次启动时就会缓存节点内容到Cache中。
经过试验,发现注册监听之后,如果先后多次修改监听节点的内容,部分监听事件会发生丢失现象。其他版本未验证,此版本此处需特别留意。
NodeCache不仅可以监听节点内容变化,还可以监听指定节点是否存在。如果原本节点不存在,那么Cache就会在节点被创建时触发监听事件,如果该节点被删除,就无法再触发监听事件。
PathChildrenCache
PathChildrenCache用于监听数据节点子节点的变化情况。当前版本总共提供了7个构造方法,其中2个已经不建议使用了。
public PathChildrenCache(CuratorFramework client, String path, boolean cacheData) public PathChildrenCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, final CloseableExecutorService executorService) public PathChildrenCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, final ExecutorService executorService) public PathChildrenCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, ThreadFactory threadFactory) public PathChildrenCache(CuratorFramework client, String path, boolean cacheData, ThreadFactory threadFactory)
常见的参数就不再具体说明了。其中cacheData表示是否把节点内容缓存起来,如果为true,那么接收到节点列表变更的同时会将获得节点内容。
ExecutorService 和threadFactory提供了通过线程池的方式来处理监听事件。
PathChildrenCache使用PathChildrenCacheListener来处理监听事件。具体使用方法见代码实例:
package com.secbro.learn.curator; import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode; /**
* Created by zhuzs on 2017/4/15.
*/
public class CuratorPathChildrenCacheTest { public static void main(String[] args) throws Exception { CuratorFramework client = getClient();
String parentPath = "/p1"; PathChildrenCache pathChildrenCache = new PathChildrenCache(client,parentPath,true);
pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {
System.out.println("事件类型:" + event.getType() + ";操作节点:" + event.getData().getPath());
}
}); String path = "/p1/c1";
client.create().withMode(CreateMode.PERSISTENT).forPath(path);
Thread.sleep(1000); // 此处需留意,如果没有现成睡眠则无法触发监听事件
client.delete().forPath(path); Thread.sleep(15000); } private static CuratorFramework getClient(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181")
.retryPolicy(retryPolicy)
.sessionTimeoutMs(6000)
.connectionTimeoutMs(3000)
.namespace("demo")
.build();
client.start();
return client;
}
}
打印结果为:
事件类型:CHILD_ADDED;操作节点:/p1/c1
事件类型:CHILD_REMOVED;操作节点:/p1/c1
PathChildrenCache不会对二级子节点进行监听,只会对子节点进行监听。看上面的实例会发现在创建子节点和删除子节点两个操作中间使用了线程睡眠,否则无法接收到监听事件,这也是在使用过程中需要留意的一点。
Zookeeper开源客户端Curator之事件监听详解的更多相关文章
- Apache Zookeeper Java客户端Curator使用及权限模式详解
这篇文章是让大家了解Zookeeper基于Java客户端Curator的基本操作,以及如何使用Zookeeper解决实际问题. Zookeeper基于Java访问 针对zookeeper,比较常用的J ...
- 八:Zookeeper开源客户端Curator的api测试
curator是Netflix公司开源的一套ZooKeeper客户端,Curator解决了很多ZooKeeper客户端非常底层的细节开发工作.包括连接重连,反复注册Watcher等.实现了Fluent ...
- Zookeeper开源客户端Curator的使用
开源zk客户端-Curator 创建会话: RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3); CuratorFramewor ...
- Zookeeper开源客户端Curator之创建会话
前面Zookeeper的链接使用的都是其提供的原生代码,实际开发过程中非常底层的细节开发工作如连接重连,反复注册等耗费开发人员大量的工作精力并且重复工作.而开源客户端Curator的出现解决了该类问题 ...
- zookeeper开源客户端curator
zookeeper的原生api相对来说比较繁琐,比如:对节点添加监听事件,当监听触发后,我们需要再次手动添加监听,否则监听只生效一次:再比如,断线重连也需要我们手动代码来判断处理等等.对于curato ...
- Zookeeper Curator 事件监听 - 秒懂
目录 写在前面 1.1. Curator 事件监听 1.1.1. Watcher 标准的事件处理器 1.1.2. NodeCache 节点缓存的监听 1.1.3. PathChildrenCache ...
- Zookeeper开源客户端框架Curator简介
Curator是Netflix开源的一套ZooKeeper客户端框架. Netflix在使用ZooKeeper的过程中发现ZooKeeper自带的客户端太底层, 应用方在使用的时候需要自己处理很多事情 ...
- Zookeeper开源客户端框架Curator简介[转]
Curator是Netflix开源的一套ZooKeeper客户端框架. Netflix在使用ZooKeeper的过程中发现ZooKeeper自带的客户端太底层, 应用方在使用的时候需要自己处理很多事情 ...
- Halo 开源项目学习(六):事件监听机制
基本介绍 Halo 项目中,当用户或博主执行某些操作时,服务器会发布相应的事件,例如博主登录管理员后台时发布 "日志记录" 事件,用户浏览文章时发布 "访问文章" ...
随机推荐
- javaweb+上传大文件
我们平时经常做的是上传文件,上传文件夹与上传文件类似,但也有一些不同之处,这次做了上传文件夹就记录下以备后用. 这次项目的需求: 支持大文件的上传和续传,要求续传支持所有浏览器,包括ie6,ie7,i ...
- linux产看磁盘信息命令-lsblk,blkid,dumpe2fs
一.lsblk命令用于列出所有可用块设备的信息,而且还能显示他们之间的依赖关系,但是它不会列出RAM盘的信息.块设备有硬盘,闪存盘,cd-ROM等等.lsblk命令包含在util-linux-ng包中 ...
- The 2019 ICPC China Nanchang National Invitational and International Silk-Road Programming Contest
目录 Contest Info Solutions A. Attack B. Polynomial E. Interesting Trip F. Sequence G. Winner H. Anoth ...
- TensorFlow(一):准备
我的环境:win10+python3.6.4(64位) 一:安装python 根据自己的电脑下载python(32位或者64位)-->安装教程 安装好python后记得配置pip源,使用官方的源 ...
- ros python 构造 pose
#!/usr/bin/env python import numpy as npfrom geometry_msgs.msg import Pose, Point, Quaternion, Twist ...
- nodejs爬虫案例笔记
用nodeJs制作一个简单的网页爬虫 主要分为三个步骤,向目标请求数据,处理数据,打印数据.需要用到的模块有http,cheerio. 1.准备步骤,引入要使用的模块 2.向目标请求数据 http.g ...
- 超轻量级虚拟终端sakura和tilda
一.安装: manjaro:pacman -S sakura ubunt:sudo apt install sakura 小当然是他的最大优点了,虽小但是功能挺全 可以同时打开好多个终端,termin ...
- 字节组数(二进制流)、Base64、图片(文件)、二进制相互之间转换
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; ...
- Java 关于日期加一天(日期往后多一天)
1.原来Java的日期添加不像.NET的.Add: import java.util.Date ; Date date=new Date();//取时间System.out.println(dat ...
- 安装openssh-server报Depends: openssh-client (= 1:6.6p1-2ubuntu2.8)错误
SFTP称作“安全的FTP”,它使用ssh文件传输协议.所以我们需要安装openssh-server ubuntu自带的有openssh-client,所以可以通过 ssh username@host ...