一、zkClient使用的原因
1)zookeeper原生API使用中,经常会遇到session expire这类异常,异常发生后需要进行重新连接,重新建立session,会比较麻烦
2)zookeeper的watcher机制是一次性的,如果你想订阅节点的状态变化、子节点变化等,每次在处理完变化事件之后,需要重新注册watcher。可想而知这是一件令人绝望的事情。这个特性使得在处理事件和重新加上watcher这段时间发生的节点变化将无法被感知。
3)zookeeper的API接口中,节点数据默认为二进制byte数组,如果想直接保存对象类型的数据,需要相关的序列化工作。
以上问题,zkClient可以很好的解决。
二、引入依赖
ZkClient目前有两个不同artifactId的系列。
其中最早的0.1版本maven依赖如下:
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
另外一个系列为的maven依赖为:
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
三、使用
在使用zkClient之前,需要先实例化一个zkClient对象,指定zookeeper地址以及超时时间。
ZkClient zkClient=new ZkClient("localhost:2181",2000);
简单实例(与zookeeper原生API大同小异)
//创建节点
zkClient.createPersistent("/docRoot");
//创建子节点
zkClient.createPersistent("/docRoot/child","child data");
//获得子节点
List<String> childList=zkClient.getChildren("/docRoot");
//获得子节点个数
int childCount=zkClient.countChildren("/docRoot");
//判断节点是否存在
boolean flag=zkClient.exists("/docRoot/child");
//写入节点数据
zkClient.writeData("/docRoot/child","child data changed");
//读取节点数据
Object obj=zkClient.readData("/docRoot/child");
//删除节点(删除父节点之前,需要删除其子节点)
zkClient.delete("/docRoot/child2");
zkClient将zookeeper的watcher机制转换为一种更加容易理解的订阅形式,并且这种关系是可以保持的,而非一次性的。也就是说,当watcher使用完后,zkclient会自动再增加一个相同的watcher。zkClient将变化事件重新定义为可供订阅的三种状态,一类是子节点的变化,一类是数据的变化,还有一类是状态的变化。
1)订阅子节点状态的变化
zkClient.subscribeChildChanges("/docRoot", new IZkChildListener() {
public void handleChildChange(String parentPath, List<String> list) throws Exception {
String s="";
for(String str:list){
s+=str+",";
}
System.out.println("子节点变化:"+s);
}
});
2)订阅节点数据的变化
zkClient.subscribeDataChanges("/docRoot", new IZkDataListener() {
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println("节点数据变化:"+dataPath+"-数据:"+data.toString());
}
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("节点数据删除:"+dataPath);
}
});
3)订阅节点连接及状态的变化情况
zkClient.subscribeStateChanges(new IZkStateListener() {
public void handleStateChanged(Watcher.Event.KeeperState keeperState) throws Exception {
System.out.println("节点连接及状态变化:"+keeperState.name());
}
public void handleNewSession() throws Exception {
System.out.println("节点Session变化。。。");
}
});
当发生session expire异常进行重连时,由于原来的所有watcher和EPHEMERAL节点都已失效,可以在handleNewSession方法中进行相应的容错处理