if (Event.KeeperState.SyncConnected == state) {
Event.EventType type = watchedEvent.getType();
if (Event.EventType.None == type) {
System.out.println("zk客户端已连接...");
}
}
}
});
zooKeeper.create("/java", "Hello World".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("新增ZNode成功");
zooKeeper.close();
}
创建一个持久性ZNode,路径是/java,值为"Hello World":
![](https://upload-images.jianshu.io/upload_images/24195226-f9f90a5e25c7c34c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
# 七、API概述
## 7.1 创建
public String create(final String path, byte data[], List acl, CreateMode createMode)
参数解释:
* path ZNode路径
* data ZNode存储的数据
* acl ACL权限控制
* createMode ZNode类型
ACL权限控制,有三个是ZooKeeper定义的常用权限,在ZooDefs.Ids类中:
/**
- This is a completely open ACL.
- 完全开放的ACL,任何连接的客户端都可以操作该属性znode
*/
public final ArrayList OPEN_ACL_UNSAFE = new ArrayList(Collections.singletonList(new ACL(Perms.ALL, ANYONE_ID_UNSAFE)));
/**
- This ACL gives the creators authentication id’s all permissions.
- 只有创建者才有ACL权限
*/
public final ArrayList CREATOR_ALL_ACL = new ArrayList(Collections.singletonList(new ACL(Perms.ALL, AUTH_IDS)));
/**
- This ACL gives the world the ability to read.
- 只能读取ACL
*/
public final ArrayList READ_ACL_UNSAFE = new ArrayList(Collections.singletonList(new ACL(Perms.READ, ANYONE_ID_UNSAFE)));
createMode就是前面讲过的四种ZNode类型:
public enum CreateMode {
/**
* 持久性ZNode
/
PERSISTENT (0, false, false),
/*
* 持久性自动增加顺序号ZNode
/
PERSISTENT_SEQUENTIAL (2, false, true),
/*
* 临时性ZNode
/
EPHEMERAL (1, true, false),
/*
* 临时性自动增加顺序号ZNode
*/
EPHEMERAL_SEQUENTIAL (3, true, true);
}
## 7.2 查询
//同步获取节点数据
public byte[] getData(String path, boolean watch, Stat stat){
…
}
//异步获取节点数据
public void getData(final String path, Watcher watcher, DataCallback cb, Object ctx){
…
}
同步getData()方法中的stat参数是用于接收返回的节点描述信息:
public byte[] getData(final String path, Watcher watcher, Stat stat){
//省略…
GetDataResponse response = new GetDataResponse();
//发送请求到ZooKeeper服务器,获取到response
ReplyHeader r = cnxn.submitRequest(h, request, response, wcb);
if (stat != null) {
//把response的Stat赋值到传入的stat中
DataTree.copyStat(response.getStat(), stat);
}
}
使用同步getData()获取数据:
//数据的描述信息,包括版本号,ACL权限,子节点信息等等
Stat stat = new Stat();
//返回结果是byte[]数据,getData()方法底层会把描述信息复制到stat对象中
byte[] bytes = zooKeeper.getData("/java", false, stat);
//打印结果
System.out.println("ZNode的数据data:" + new String(bytes));//Hello World
System.out.println("获取到dataVersion版本号:" + stat.getVersion());//默认数据版本号是0
## 7.3 更新
public Stat setData(final String path, byte data[], int version){
…
}
值得注意的是第三个参数version,**使用CAS机制,这是为了防止多个客户端同时更新节点数据,所以需要在更新时传入版本号,每次更新都会使版本号+1**,如果服务端接收到版本号,对比发现不一致的话,则会抛出异常。
所以,在更新前需要先查询获取到版本号,否则你不知道当前版本号是多少,就没法更新:
//获取节点描述信息
Stat stat = new Stat();
zooKeeper.getData("/java", false, stat);
System.out.println("更新ZNode数据...");
//更新操作,传入路径,更新值,版本号三个参数,返回结果是新的描述信息
Stat setData = zooKeeper.setData("/java", "fly!!!".getBytes(), stat.getVersion());
System.out.println("更新后的版本号为:" + setData.getVersion());//更新后的版本号为:1
更新后,版本号增加了:
![](https://upload-images.jianshu.io/upload_images/24195226-99b96debd2050544.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
如果传入的版本参数是"-1",就是告诉zookeeper服务器,客户端需要基于数据的最新版本进行更新操作。但是-1并不是一个合法的版本号,而是一个标识符。
## 7.4 删除
public void delete(final String path, int version){
…
}
* path 删除节点的路径
* version 版本号
这里也需要传入版本号,调用getData()方法即可获取到版本号,很简单:
Stat stat = new Stat();
zooKeeper.getData("/java", false, stat);
//删除ZNode
zooKeeper.delete("/java", stat.getVersion());
## 7.5 watcher机制
在上面第三点提到,ZooKeeper是可以使用通知监听机制,当ZNode发生变化会收到通知消息,进行处理。基于watcher机制,ZooKeeper能玩出很多花样。怎么使用?
ZooKeeper的通知监听机制,总的来说可以分为三个过程:
①客户端注册 Watcher ②服务器处理 Watcher ③客户端回调 Watcher客户端。
注册 watcher 有 4 种方法,new ZooKeeper()、getData()、exists()、getChildren()。下面演示一下使用exists()方法注册watcher:
首先**需要实现Watcher接口**,新建一个监听器:
public class MyWatcher implements Watcher {
@Override
public void process(WatchedEvent event) {
//获取事件类型
Event.EventType eventType = event.getType();
//通知状态
Event.KeeperState eventState = event.getState();
//节点路径
String eventPath = event.getPath();
System.out.println(“监听到的事件类型:” + eventType.name());
System.out.println(“监听到的通知状态:” + eventState.name());
System.out.println(“监听到的ZNode路径:” + eventPath);
}
}
然后调用exists()方法,注册监听器:
zooKeeper.exists("/java", new MyWatcher());
//对ZNode进行更新数据的操作,触发监听器
zooKeeper.setData("/java", “fly”.getBytes(), -1);
然后在控制台就可以看到打印的信息:
![](https://upload-images.jianshu.io/upload_images/24195226-6d4f24d7fe63fffe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
这里我们可以看到**Event.EventType对象就是事件类型**,我们可以对事件类型进行判断,再配合**Event.KeeperState通知状态**,做相关的业务处理,事件类型有哪些?
打开EventType、KeeperState的源码查看:
//事件类型是一个枚举
public enum EventType {
None (-1),//无
NodeCreated (1),//Watcher监听的数据节点被创建
NodeDeleted (2),//Watcher监听的数据节点被删除
NodeDataChanged (3),//Watcher监听的数据节点内容发生变更
NodeChildrenChanged (4);//Watcher监听的数据节点的子节点列表发生变更
}
//通知状态也是一个枚举
public enum KeeperState {
Unknown (-1),//属性过期
Disconnected (0),//客户端与服务端断开连接
NoSyncConnected (1),//属性过期
SyncConnected (3),//客户端与服务端正常连接
AuthFailed (4),//身份认证失败
ConnectedReadOnly (5),//返回这个状态给客户端,客户端只能处理读请求
SaslAuthenticated(6),//服务器采用SASL做校验时
Expired (-112);//会话session失效
}
### 7.5.1 watcher的特性
* 一次性。一旦watcher被触发,ZK都会从相应的存储中移除。
最后
在面试前我整理归纳了一些面试学习资料,文中结合我的朋友同学面试美团滴滴这类大厂的资料及案例
感兴趣的朋友可以点击Java学习免费获取。
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
大家看完有什么不懂的可以在下方留言讨论也可以关注。
觉得文章对你有帮助的话记得关注我点个赞支持一下!
的朋友可以点击Java学习免费获取。**
[外链图片转存中…(img-Gpya0PlO-1628624732493)]
[外链图片转存中…(img-7cXBSwku-1628624732496)]
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
大家看完有什么不懂的可以在下方留言讨论也可以关注。
觉得文章对你有帮助的话记得关注我点个赞支持一下!