Zookeeper的Api使用
Zookeeper api
Zookeeper API共包含五个包,分别为:
(1)org.apache.zookeeper
(2)org.apache.zookeeper.data
(3)org.apache.zookeeper.server
(4)org.apache.zookeeper.server.quorum
(5)org.apache.zookeeper.server.upgrade
其中org.apache.zookeeper,包含Zookeeper类,他是我们编程时最常⽤的类⽂件。这个类是Zookeeper客户端的主要类⽂件。如果要使⽤Zookeeper服务,应⽤程序⾸先必须创建⼀个Zookeeper实例,这时就需要使⽤此类。⼀旦客户端和Zookeeper服务端建⽴起了连接,Zookeeper系统将会给本次连接会话分配⼀个ID值,并且客户端将会周期性的向服务器端发送⼼跳来维持会话连接。只要连接有效,客户端就可以使⽤Zookeeper API来做相应处理了。
准备⼯作:导⼊依赖
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
</dependency>
建立会话
public class CreateSession implements Watcher {
private static final CountDownLatch countDownLatch = new CountDownLatch(1);
public static void main(String[] args) throws IOException, InterruptedException {
/*
客户端可以通过创建一个zk实例来连接zk服务器
new Zookeeper(connectString,sesssionTimeOut,Wather)
connectString: 连接地址:IP:端口
sesssionTimeOut:会话超时时间:单位毫秒
Wather:监听器(当特定事件触发监听时,zk会通过watcher通知到客户端)
*/
ZooKeeper zooKeeper = new ZooKeeper("8.129.124.193:2181",5000,new CreateSession());
System.out.println(zooKeeper.getState());
countDownLatch.await();
System.out.println("=========Client Connected to zookeeper==========");
}
@Override
public void process(WatchedEvent watchedEvent) {
//当连接创建了,服务端发送给客户端SyncConnected事件
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
countDownLatch.countDown();
System.out.println("连接成功");
}
}
}
注意,ZooKeeper 客户端和服务端会话的建⽴是⼀个异步的过程,也就是说在程序中,构造⽅法会在处理完客户端初始化⼯作后⽴即返回,在⼤多数情况下,此时并没有真正建⽴好⼀个可⽤的会话,在会话的⽣命周期中处于“CONNECTING”的状态。 当该会话真正创建完毕后ZooKeeper服务端会向会话对应的客户端发送⼀个事件通知,以告知客户端,客户端只有在获取这个通知之后,才算真正建⽴了会话。
创建节点
public class CreateNote implements Watcher {
private static ZooKeeper zooKeeper = null;
public static void main(String[] args) throws IOException, InterruptedException {
zooKeeper = new ZooKeeper("8.129.124.193:2181", 5000, new CreateNote());
// countDownLatch.await();
System.out.println("=========Client Connected to zookeeper==========");
Thread.sleep(Integer.MAX_VALUE);
}
@Override
public void process(WatchedEvent watchedEvent) {
//当连接创建了,服务端发送给客户端SyncConnected事件
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
// countDownLatch.countDown();
System.out.println("连接成功");
}
try {
createNoteSync();
} catch (Exception e) {
e.printStackTrace();
}
}
public void createNoteSync() throws Exception {
/**
* path :节点创建的路径
* data[] :节点创建要保存的数据,是个byte类型的
* acl :节点创建的权限信息(4种类型)
* ANYONE_ID_UNSAFE : 表示任何⼈
* AUTH_IDS :此ID仅可⽤于设置ACL。它将被客户机验证的ID替
换。
* OPEN_ACL_UNSAFE :这是⼀个完全开放的ACL(常⽤)-->
world:anyone
* CREATOR_ALL_ACL :此ACL授予创建者身份验证ID的所有权限
* createMode :创建节点的类型(4种类型)
* PERSISTENT:持久节点
* PERSISTENT_SEQUENTIAL:持久顺序节点
* EPHEMERAL:临时节点
* EPHEMERAL_SEQUENTIAL:临时顺序节点
String node = zookeeper.create(path,data,acl,createMode);
*/
String persistentNode = zooKeeper.create("/jerry", "jerry的持久性节点".getBytes("UTF8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
String persistentSequentialNode = zooKeeper.create("/jerry_sequncetial", "jerry的持久性顺序节点".getBytes("UTF8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
String ephemeralNode = zooKeeper.create("/jerry_ephemeral", "jerry的临时节点".getBytes("UTF8"), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
System.out.println("创建的持久性节点:" + persistentNode);
System.out.println("创建的持久性顺序节点:" + persistentSequentialNode);
System.out.println("创建的临时节点:" + ephemeralNode);
}
}
获取节点数据
public class getNoteData implements Watcher {
private static ZooKeeper zooKeeper = null;
public static void main(String[] args) throws IOException, InterruptedException {
zooKeeper = new ZooKeeper("8.129.124.193:2181", 5000, new getNoteData());
// countDownLatch.await();
System.out.println("=========Client Connected to zookeeper==========");
Thread.sleep(Integer.MAX_VALUE);
}
@Override
public void process(WatchedEvent watchedEvent) {
//当连接创建了,服务端发送给客户端SyncConnected事件
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
System.out.println("连接成功");
try {
getNoteData();
getChildrens();
} catch (Exception e) {
e.printStackTrace();
}
}
if(watchedEvent.getType() == Event.EventType.NodeChildrenChanged) {
try {
List<String> children = zooKeeper.getChildren(watchedEvent.getPath(), true);
System.out.println(children);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
获取某个节点的内容
*/
private void getNoteData() throws KeeperException, InterruptedException {
/**
* path : 获取数据的路径
* watch : 是否开启监听
* stat : 节点状态信息
* null: 表示获取最新版本的数据
* zk.getData(path, watch, stat);
*/
byte[] data = zooKeeper.getData("/jerry", false, null);
System.out.println(new String(data));
}
/*
获取某个节点的子节点列表方法
*/
public static void getChildrens() throws KeeperException, InterruptedException {
/*
path:路径
watch:是否要启动监听,当子节点列表发生变化,会触发监听
zooKeeper.getChildren(path, watch);
*/
List<String> children = zooKeeper.getChildren("/jerry", true);
System.out.println(children);
}
}
修改节点数据
public class UpdateNoteData implements Watcher {
private static ZooKeeper zooKeeper;
/*
建立会话
*/
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
/*
客户端可以通过创建一个zk实例来连接zk服务器
new Zookeeper(connectString,sesssionTimeOut,Wather)
connectString: 连接地址:IP:端口
sesssionTimeOut:会话超时时间:单位毫秒
Wather:监听器(当特定事件触发监听时,zk会通过watcher通知到客户端)
*/
zooKeeper = new ZooKeeper("8.129.124.193:2181", 5000, new UpdateNoteData());
System.out.println(zooKeeper.getState());
// 计数工具类:CountDownLatch:不让main方法结束,让线程处于等待阻塞
//countDownLatch.await();\
Thread.sleep(Integer.MAX_VALUE);
}
/*
回调方法:处理来自服务器端的watcher通知
*/
public void process(WatchedEvent watchedEvent) {
// SyncConnected
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
//解除主程序在CountDownLatch上的等待阻塞
System.out.println("process方法执行了...");
// 更新数据节点内容的方法
try {
updateNoteSync();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
更新数据节点内容的方法
*/
private void updateNoteSync() throws Exception {
/*
path:路径
data:要修改的内容 byte[]
version:为-1,表示对最新版本的数据进行修改
zooKeeper.setData(path, data,version);
*/
byte[] data = zooKeeper.getData("/jerry", false, null);
System.out.println("修改前的值:" + new String(data));
//修改/lg-persistent 的数据 stat: 状态信息对象
Stat stat = zooKeeper.setData("/jerry", "客户端修改了节点数据".getBytes("UTF8"), -1);
byte[] data2 = zooKeeper.getData("/jerry", false, null);
System.out.println("修改后的值:" + new String(data2));
}
}
删除节点
public class DeleteNote implements Watcher {
private static ZooKeeper zooKeeper;
/*
建立会话
*/
public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
/*
客户端可以通过创建一个zk实例来连接zk服务器
new Zookeeper(connectString,sesssionTimeOut,Wather)
connectString: 连接地址:IP:端口
sesssionTimeOut:会话超时时间:单位毫秒
Wather:监听器(当特定事件触发监听时,zk会通过watcher通知到客户端)
*/
zooKeeper = new ZooKeeper("8.129.124.193:2181", 5000, new DeleteNote());
System.out.println(zooKeeper.getState());
Thread.sleep(Integer.MAX_VALUE);
}
/*
回调方法:处理来自服务器端的watcher通知
*/
public void process(WatchedEvent watchedEvent) {
// SyncConnected
if(watchedEvent.getState() == Event.KeeperState.SyncConnected){
//解除主程序在CountDownLatch上的等待阻塞
System.out.println("process方法执行了...");
// 删除节点
try {
deleteNoteSync();
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
删除节点的方法
*/
private void deleteNoteSync() throws KeeperException, InterruptedException {
/*
zooKeeper.exists(path,watch) :判断节点是否存在
zookeeper.delete(path,version) : 删除节点
*/
Stat stat = zooKeeper.exists("/jerry/jerry_child0000000000", false);
System.out.println(stat == null ? "该节点不存在":"该节点存在");
if(stat != null){
zooKeeper.delete("/jerry/jerry_child0000000000",-1);
}
Stat stat2 = zooKeeper.exists("/jerry/jerry_child0000000000", false);
System.out.println(stat2 == null ? "该节点不存在":"该节点存在");
}
}
Zookeeper-开源客户端
ZkClient
ZkClient是Github上⼀个开源的zookeeper客户端,在Zookeeper原⽣API接⼝之上进⾏了包装,是⼀个更易⽤的Zookeeper客户端,同时,zkClient在内部还实现了诸如Session超时重连、Watcher反复注册等功能接下来,还是从创建会话、创建节点、读取数据、更新数据、删除节点等⽅⾯来介绍如何使⽤zkClient。
添加依赖:
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.2</version>
</dependency>
创建会话:
public class CreateSession {
/*
借助zkclient完成会话的创建
*/
public static void main(String[] args) {
/*
创建一个zkclient实例就可以完成连接,完成会话的创建
serverString : 服务器连接地址
注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
*/
ZkClient zkClient = new ZkClient("8.129.124.193:2181");
System.out.println("会话被创建了..");
}
}
创建节点
public class Create_Note {
/*
借助zkclient完成会话的创建
*/
public static void main(String[] args) {
/*
创建一个zkclient实例就可以完成连接,完成会话的创建
serverString : 服务器连接地址
注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
*/
ZkClient zkClient = new ZkClient("8.129.124.193:2181");
System.out.println("会话被创建了..");
//创建节点
/*
cereateParents : 是否要创建父节点,如果值为true,那么就会递归创建节点
*/
zkClient.createPersistent("/jerry/jerry_child1",true);
System.out.println("节点递归创建完成");
}
}
注意,在原⽣态接⼝中是⽆法创建成功的(⽗节点不存在),但是通过ZkClient通过设置createParents参数为true可以递归的先创建⽗节点,再创建⼦节点。
删除节点
ZkClient提供了递归删除节点的接⼝,即其帮助开发者先删除所有⼦节点(存在),再删除⽗节点。在pom.xml⽂件中添加如下内容。
public class Delete_Note {
/*
借助zkclient完成会话的创建
*/
public static void main(String[] args) {
/*
创建一个zkclient实例就可以完成连接,完成会话的创建
serverString : 服务器连接地址
注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
*/
ZkClient zkClient = new ZkClient("8.129.124.193:2181");
System.out.println("会话被创建了..");
// 递归删除节点
String path = "/jerry/jerry_child1";
zkClient.createPersistent(path+"/c11");
zkClient.deleteRecursive(path);
System.out.println("递归删除成功");
}
}
ZkClient可直接删除带⼦节点的⽗节点,因为其底层先删除其所有⼦节点,然后再删除⽗节点。
获取⼦节点
public class Get_NoteChildren {
/*
借助zkclient完成会话的创建
*/
public static void main(String[] args) throws InterruptedException {
/*
创建一个zkclient实例就可以完成连接,完成会话的创建
serverString : 服务器连接地址
注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
*/
ZkClient zkClient = new ZkClient("8.129.124.193:2181");
System.out.println("会话被创建了..");
// 获取子节点列表
List<String> children = zkClient.getChildren("/lg-zkclient");
System.out.println(children);
// 注册监听事件
/*
客户端可以对一个不存在的节点进行子节点变更的监听
只要该节点的子节点列表发生变化,或者该节点本身被创建或者删除,都会触发监听
*/
zkClient.subscribeChildChanges("/lg-zkclient-get", new IZkChildListener() {
/*
s : parentPath
list : 变化后子节点列表
*/
public void handleChildChange(String parentPath, List<String> list) throws Exception {
System.out.println(parentPath + "的子节点列表发生了变化,变化后的子节点列表为"+ list);
}
});
//测试
zkClient.createPersistent("/lg-zkclient-get");
Thread.sleep(1000);
zkClient.createPersistent("/lg-zkclient-get/c1");
Thread.sleep(1000);
}
}
客户端可以对⼀个不存在的节点进⾏⼦节点变更的监听。⼀旦客户端对⼀个节点注册了⼦节点列表变更监听之后,那么当该节点的⼦节点列表发⽣变更时,服务端都会通知客户端,并将最新的⼦节点列表发送给客户端;该节点本身的创建或删除也会通知到客户端。
获取数据(节点是否存在、更新、删除)
public class Note_API {
/*
借助zkclient完成会话的创建
*/
public static void main(String[] args) throws InterruptedException {
/*
创建一个zkclient实例就可以完成连接,完成会话的创建
serverString : 服务器连接地址
注意:zkClient通过对zookeeperAPI内部封装,将这个异步创建会话的过程同步化了..
*/
ZkClient zkClient = new ZkClient("8.129.124.193:2181");
System.out.println("会话被创建了..");
// 判断节点是否存在
String path = "jerry-ep";
boolean exists = zkClient.exists(path);
if(!exists){
// 创建临时节点
zkClient.createEphemeral(path,"123");
}
// 读取节点内容
Object o = zkClient.readData(path);
System.out.println(o);
// 注册监听
zkClient.subscribeDataChanges(path, new IZkDataListener() {
/*
当节点数据内容发生变化时,执行的回调方法
s: path
o: 变化后的节点内容
*/
public void handleDataChange(String s, Object o) throws Exception {
System.out.println(s+"该节点内容被更新,更新的内容"+o);
}
/*
当节点被删除时,会执行的回调方法
s : path
*/
public void handleDataDeleted(String s) throws Exception {
System.out.println(s+"该节点被删除");
}
});
// 更新节点内容
zkClient.writeData(path,"456");
Thread.sleep(1000);
// 删除节点
zkClient.delete(path);
Thread.sleep(1000);
exists = zkClient.exists(path);
if(!exists){
// 创建临时节点
zkClient.createEphemeral(path,"jerry");
}
// 读取节点内容
o = zkClient.readData(path);
System.out.println(o);
}
}
Curator客户端
curator是Netflix公司开源的⼀套Zookeeper客户端框架,和ZKClient⼀样,Curator解决了很多Zookeeper客户端⾮常底层的细节开发⼯作,包括连接重连,反复注册Watcher和NodeExistsException异常等,是最流⾏的Zookeeper客户端之⼀。从编码⻛格上来讲,它提供了基于Fluent的编程⻛格⽀持。
添加依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
创建会话
Curator的创建会话⽅式与原⽣的API和ZkClient的创建⽅式区别很⼤。Curator创建客户端是通过CuratorFrameworkFactory⼯⼚类来实现的。具体如下:
1.使⽤CuratorFramework这个⼯⼚类的两个静态⽅法来创建⼀个客户端
public static CuratorFramework newClient(String connectString, RetryPolicy retryPolicy)
public static CuratorFramework newClient(String connectString, int sessionTimeoutMs, int connectionTimeoutMs, RetryPolicy retryPolicy)
其中参数RetryPolicy提供重试策略的接⼝,可以让⽤户实现⾃定义的重试策略,默认提供了以下实现,分别为ExponentialBackoffRetry(基于backoff的重连策略)、RetryNTimes(重连N次策略)、RetryForever(永远重试策略)。
2.通过调⽤CuratorFramework中的start()⽅法来启动会话
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",retryPolicy);
client.start();
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181",
5000,1000,retryPolicy);
client.start();
其实进⼀步查看源代码可以得知,其实这两种⽅法内部实现⼀样,只是对外包装成不同的⽅法。它们的底层都是通过第三个⽅法builder来实现的
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,3);
private static CuratorFramework Client = CuratorFrameworkFactory.builder()
.connectString("server1:2181,server2:2181,server3:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(retryPolicy)
.build();
client.start();
参数:
- connectString:zk的server地址,多个server之间使⽤英⽂逗号分隔开
- connectionTimeoutMs:连接超时时间,如上是30s,默认是15s
- sessionTimeoutMs:会话超时时间,如上是50s,默认是60s
- retryPolicy:失败重试策略
-
ExponentialBackoffRetry:构造器含有三个参数 ExponentialBackoffRetry(int baseSleepTimeMs, int maxRetries, int maxSleepMs) baseSleepTimeMs:初始的sleep时间,⽤于计算之后的每次重试的sleep时间, 计算公式:当前sleep时间=baseSleepTimeMs*Math.max(1,random.nextInt(1<<(retryCount+1))) maxRetries:最⼤重试次数 maxSleepMs:最⼤sleep时间,如果上述的当前sleep计算出来⽐这个⼤,那么sleep⽤这个时间,默认的最⼤时间是Integer.MAX_VALUE毫秒。
- start():完成会话的创建
创建节点
curator提供了⼀系列Fluent⻛格的接⼝,通过使⽤Fluent编程⻛格的接⼝,开发⼈员可以进⾏⾃由组合来完成各种类型节点的创建。
下⾯简单介绍⼀下常⽤的⼏个节点创建场景。
(1)创建⼀个初始内容为空的节点
client.create().forPath(path);
Curator默认创建的是持久节点,内容为空
(2)创建⼀个包含内容的节点
client.create().forPath(path,"我是内容".getBytes());
Curator和ZkClient不同的是依旧采⽤Zookeeper原⽣API的⻛格,内容使⽤byte[]作为⽅法参数。
(3)递归创建⽗节点,并选择节点类型
client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path);
creatingParentsIfNeeded这个接⼝⾮常有⽤,在使⽤ZooKeeper 的过程中,开发⼈员经常会碰到NoNodeException 异常,其中⼀个可能的原因就是试图对⼀个不存在的⽗节点创建⼦节点。因此,开发⼈员不得不在每次创建节点之前,都判断⼀下该⽗节点是否存在——这个处理通常⽐较麻烦。在使⽤Curator 之后,通过调⽤creatingParentsIfNeeded 接⼝,Curator 就能够⾃动地递归创建所有需要的⽗节点。
public class CreateNote_curator {
// 创建会话
public static void main(String[] args) throws Exception {
//不使用fluent编程风格
RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
// 使用fluent编程风格
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("8.129.124.193:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(exponentialBackoffRetry)
.namespace("base") // 独立的命名空间 /base
.build();
client.start();
System.out.println("会话2创建了");
// 创建节点
String path = "/jerry-curator/c1";
String s = client.create().creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT).forPath(path, "init".getBytes());
System.out.println("节点递归创建成功,该节点路径" + s);
}
}
删除节点
删除节点的⽅法也是基于Fluent⽅式来进⾏操作,不同类型的操作调⽤ 新增不同的⽅法调⽤即可。
(1)删除⼀个⼦节点
client.delete().forPath(path);
(2)删除节点并递归删除其⼦节点
client.delete().deletingChildrenIfNeeded().forPath(path);
(3)指定版本进⾏删除
client.delete().withVersion(1).forPath(path);
如果此版本已经不存在,则删除异常,异常信息如下。
org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for
(4)强制保证删除⼀个节点
client.delete().guaranteed().forPath(path);
只要客户端会话有效,那么Curator会在后台持续进⾏删除操作,直到节点删除成功。⽐如遇到⼀些⽹络异常的情况,此guaranteed的强制删除就会很有效果。
public class DeleteNote_curator {
// 创建会话
public static void main(String[] args) throws Exception {
// 使用fluent编程风格
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("8.129.124.193:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(exponentialBackoffRetry)
.namespace("base") // 独立的命名空间 /base
.build();
client.start();
System.out.println("会话2创建了");
// 删除节点
String path = "/jerry-curator";
client.delete().deletingChildrenIfNeeded().withVersion(-1).forPath(path);
System.out.println("删除成功,删除的节点" + path);
}
}
获取数据
获取节点数据内容API相当简单,同时Curator提供了传⼊⼀个Stat变量的⽅式来存储服务器端返回的最新的节点状态信息
// 普通查询
client.getData().forPath(path);
// 包含状态查询
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath(path);
public class GetNote_curator {
// 创建会话
public static void main(String[] args) throws Exception {
//不使用fluent编程风格
RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
// 使用fluent编程风格
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("8.129.124.193:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(exponentialBackoffRetry)
.namespace("base") // 独立的命名空间 /base
.build();
client.start();
System.out.println("会话2创建了");
// 创建节点
String path = "/lg-curator/c1";
String s = client.create().creatingParentsIfNeeded()
.withMode(CreateMode.PERSISTENT).forPath(path, "init".getBytes());
System.out.println("节点递归创建成功,该节点路径" + s);
// 获取节点的数据内容及状态信息
// 数据内容
byte[] bytes = client.getData().forPath(path);
System.out.println("获取到的节点数据内容:" + new String(bytes));
// 状态信息
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath(path);
System.out.println("获取到的节点状态信息:" + stat );
}
}
更新数据
更新数据,如果未传⼊version参数,那么更新当前最新版本,如果传⼊version则更新指定version,如果version已经变更,则抛出异常。
// 普通更新
client.setData().forPath(path,"新内容".getBytes());
// 指定版本更新
client.setData().withVersion(1).forPath(path);
版本不⼀致异常信息:
org.apache.zookeeper.KeeperException$BadVersionException: KeeperErrorCode = BadVersion for
public class UpdateNote_curator {
// 创建会话
public static void main(String[] args) throws Exception {
//不使用fluent编程风格
RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
// 使用fluent编程风格
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("8.129.124.193:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(exponentialBackoffRetry)
.namespace("base") // 独立的命名空间 /base
.build();
client.start();
System.out.println("会话2创建了");
// 创建节点
String path = "/lg-curator/c1";
// 获取节点的数据内容及状态信息
// 数据内容
byte[] bytes = client.getData().forPath(path);
System.out.println("获取到的节点数据内容:" + new String(bytes));
// 状态信息
Stat stat = new Stat(); //0
client.getData().storingStatIn(stat).forPath(path);
System.out.println("获取到的节点状态信息:" + stat );
// 更新节点内容 //1
int version = client.setData().withVersion(stat.getVersion()).forPath(path, "修改内容1".getBytes()).getVersion();
System.out.println("当前的最新版本是" + version);
byte[] bytes2 = client.getData().forPath(path);
System.out.println("修改后的节点数据内容:" + new String(bytes2));
// BadVersionException,stat的版本已过期
client.setData().withVersion(stat.getVersion()).forPath(path,"修改内容2".getBytes());
}
**curator事件监听
public class watchNote_curator {
private static CuratorFramework client = null;
// 创建会话
public static void main(String[] args) throws Exception {
//初始话curator
init();
watcherTest();
}
public static void init() {
//不使用fluent编程风格
RetryPolicy exponentialBackoffRetry = new ExponentialBackoffRetry(1000, 3);
// 使用fluent编程风格
CuratorFramework client = CuratorFrameworkFactory.builder()
.connectString("8.129.124.193:2181")
.sessionTimeoutMs(50000)
.connectionTimeoutMs(30000)
.retryPolicy(exponentialBackoffRetry)
.namespace("base") // 独立的命名空间 /base
.build();
client.start();
System.out.println("会话创建了");
}
public static void watcherTest() throws Exception {
// 创建节点
String path = "/jerry/c1";
Watcher watcher = new Watcher() {
public void process(WatchedEvent watchedEvent) {
Event.EventType eventType = watchedEvent.getType();
if(eventType.equals(Event.EventType.NodeDeleted)){
System.out.println("删除节点了--" + watchedEvent.getPath());
}
}
};
// 创建节点
client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/jerry/c1");
client.getChildren().usingWatcher(watcher).forPath("/jerry/c1");
client.delete().deletingChildrenIfNeeded().withVersion(-1).forPath(path);
}
}
NodeCache:对一个节点进行监听,监听事件包括指定的路径节点的增、删、改的操作。
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()));
}
});
PathChildrenCache: 对指定的路径节点的一级子目录进行监听,不对该节点的操作进行监听,对其子目录的节点进行增、删、改的操作监听
PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/msg_server_list", false);//监听msg_server_list路径下的所有节点
pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);//异步初始化
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
if (type.equals(PathChildrenCacheEvent.Type.CHILD_REMOVED)) {
System.out.println(pathChildrenCacheEvent.getData().getPath());
}
}
});
TreeCache: 可以将指定的路径节点作为根节点(祖先节点),对其所有的子节点操作进行监听,呈现树形目录的监听,可以设置监听深度,最大监听深度为2147483647(int类型的最大值)。
TreeCache treeCache = new TreeCache(client, path);
treeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
ChildData eventData = event.getData();
switch (event.getType()) {
case NODE_ADDED:
logger.warn(path + "节点添加" + eventData.getPath() + "\t添加数据为:" + new String(eventData.getData()));
break;
case NODE_UPDATED:
logger.warn(eventData.getPath() + "节点数据更新\t更新数据为:" + new String(eventData.getData()) + "\t版本为:" + eventData.getStat().getVersion());
break;
case NODE_REMOVED:
logger.warn(eventData.getPath() + "节点被删除");
break;
default:
break;
}
}
});
treeCache.start();