1 Curator客户端简介
curator是netflix公司开源的一个zk客户端,后捐赠给apache。curator框架在原生的zk api上进行了封装,隐藏了很多zookeeper客户端底层的细节,提供了zookeeper各种应用场景(分布式锁、集群领导选举、共享计数器、缓存机制、分布式队列)的抽象封装,实现了链式风格编码,是最流行的zookeeper客户端
原生zookeeper不足
- 连接对象异步,需要开发人员自己编写代码阻塞等待
- 连接没有自动重连机制
- watcher注册后只生效一次
- 不支持递归创建树形节点
curator特点
- 解决session超时重连问题
- watcher反复注册
- 简化api
- 链式编程风格
- 提供分布式锁、集群领导选举、共享计数器、缓存机制等工具类
2 代码实现
2.1 建立连接
private CuratorFramework curatorFramework = null;
@Before
public void init() throws Exception {
//1 重试策略:初试时间为3s 重试10次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
//2 通过工厂创建连接
curatorFramework = CuratorFrameworkFactory.builder()
.connectString(Constant.ZK_HOST)
.sessionTimeoutMs(Constant.SESSION_TIMEOUT)
.retryPolicy(retryPolicy)
.build();
//3 开启连接
curatorFramework.start();
}
2.2 创建节点
@Test
public void testCreate() throws Exception {
curatorFramework.create()
.withMode(CreateMode.PERSISTENT)
.forPath(Constant.ROOT_PATH, "root".getBytes());
}
@Test
public void testCreateWithParent() throws Exception {
curatorFramework.create()
.creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT)
.forPath(Constant.ROOT_PATH + "/path1", "path1".getBytes());
}
@Test
public void testCreateAsync() throws Exception {
curatorFramework.create()
.withMode(CreateMode.PERSISTENT)
.inBackground((client, event) -> {
String path = event.getPath();
String data = new String(event.getData());
System.out.println("create data end, path:" + path + ", data:" + data);
})
.forPath(Constant.ROOT_PATH, "root".getBytes());
}
2.3 查看节点
@Test
public void testGet() throws Exception {
String data = new String(curatorFramework.getData().forPath(Constant.ROOT_PATH));
System.out.println("get data:" + data);
}
@Test
public void testGetWithStat() throws Exception {
Stat stat = new Stat();
String data = new String(curatorFramework.getData().storingStatIn(stat).forPath(Constant.ROOT_PATH));
System.out.println("get data:" + data + ", version:" + stat.getVersion());
}
@Test
public void testGetAsync() throws Exception {
curatorFramework.getData()
.inBackground((client, event) -> {
String path = event.getPath();
String data = new String(event.getData());
System.out.println("get data end, path:" + path + ", data:" + data);
})
.forPath(Constant.ROOT_PATH);
}
2.4 修改节点
@Test
public void testUpdate() throws Exception {
curatorFramework.setData().forPath(Constant.ROOT_PATH, "root update".getBytes());
}
@Test
public void testUpdateWithVersion() throws Exception {
curatorFramework.setData().withVersion(1).forPath(Constant.ROOT_PATH, "root update".getBytes());
}
@Test
public void testUpdateAsync() throws Exception {
curatorFramework.setData()
.inBackground((client, event) -> {
String path = event.getPath();
String data = new String(event.getData());
System.out.println("update data end, path:" + path + ", data:" + data);
})
.forPath(Constant.ROOT_PATH, "root update".getBytes());
}
2.5 删除节点
@Test
public void testDelete() throws Exception {
curatorFramework.delete().forPath(Constant.ROOT_PATH);
}
@Test
public void testDeleteWithVersion() throws Exception {
curatorFramework.delete().withVersion(1).forPath(Constant.ROOT_PATH);
}
@Test
public void testDeleteAsync() throws Exception {
curatorFramework.delete()
.inBackground((client, event) -> {
String path = event.getPath();
String data = new String(event.getData());
System.out.println("delete data end, path:" + path + ", data:" + data);
})
.forPath(Constant.ROOT_PATH);
}
@Test
public void deleteWithChildren() throws Exception {
curatorFramework.delete().deletingChildrenIfNeeded().forPath(Constant.ROOT_PATH);
}
2.6 查看子节点
@Test
public void testGetChildren() throws Exception {
List<String> list = curatorFramework.getChildren().forPath(Constant.ROOT_PATH);
System.out.println(list);
}
@Test
public void testGetChildrenAsync() throws Exception {
curatorFramework.getChildren()
.inBackground((client, event) -> {
String path = event.getPath();
String data = new String(event.getData());
System.out.println("get data children end, path:" + path + ", data:" + data + " children:" + event.getChildren());
})
.forPath(Constant.ROOT_PATH);
}
2.7 查看节点是否存在
@Test
public void testExists() throws Exception {
Stat stat = curatorFramework.checkExists().forPath(Constant.ROOT_PATH);
}
@Test
public void testExistsAsync() throws Exception {
Stat stat = curatorFramework.checkExists()
.inBackground((client, event) -> {
System.out.println("check exists end, stat:" + event.getStat());
})
.forPath(Constant.ROOT_PATH);
}
2.8 watcher监听
@Test
public void testWatch() throws Exception {
final NodeCache cache = new NodeCache(curatorFramework, Constant.ROOT_PATH, false);
cache.start(true);
cache.getListenable().addListener(() -> {
ChildData childData = cache.getCurrentData();
if (Objects.isNull(childData)) {
log.info("data removed");
} else {
log.info("data changed, path:{}, data:{}, status:{}", childData.getPath(), childData.getData(), childData.getStat());
}
});
}
@Test
public void testWatchChildren() throws Exception {
// 建立一个PathChildrenCache缓存,第三个参数为是否接受节点数据内容 如果为false则不接受
PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFramework, Constant.ROOT_PATH, true);
pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
pathChildrenCache.getListenable().addListener((cf, event) -> {
ChildData data = event.getData();
switch (event.getType()) {
case CHILD_ADDED:
log.info("child added, path:{}, data:{}" + data.getPath(), data.getData());
break;
case CHILD_UPDATED:
log.info("child updated, path:{}, data:{}" + data.getPath(), data.getData());
break;
case CHILD_REMOVED:
log.info("child removed, path:{}, data:{}" + data.getPath(), data.getData());
break;
default:
break;
}
});
}