在上一篇中,我们讲解了ZooKeeper的相关操作命令,链接为 ZooKeeper完全解析(二) zooKeeper命令详解,这一篇中,我们将会详细的讲解如何使用Java操作ZooKeeper。
一、引入依赖与建立连接:
注意ZooKeeper连接池的版本最好与使用的ZooKeeper版本一致,比如使用的ZooKeeper版本为 3.4.13,那么引入的连接池依赖即为:
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.13</version>
</dependency>
建立连接的方法即为:
ZooKeeper zooKeeper = new ZooKeeper(ZooKeeperAdress, sessionTimeOut, Watcher());
其中:
1、ZooKeeperAdress 为zooKeeper的地址,比如 127.0.0.1:2181
2、sessionTimeOut 即为ZooKeeper等待客户端通信的最长时间,注意是ZooKeeper等待客户端,而不是客户端等待ZooKeeper,此为毫秒为单位,比如我设置此值为 10000,那么如果ZooKeeper与客户端在10秒内无法通信的话,ZooKeeper就会断开此次连接。但是如果调用zooKeeper.close()显示的关闭连接,就会立即关闭,不会等超时时间。
3、Watcher即为一个回调接口,当发生一些事件,比如连接成功,连接失败等情况,会回调此接口。
二、create(创建节点):
在zooKeeper的命令中,create为:
create [-s] [-e] [path] [value] [acl]
其中,-s为是否自动顺序创建,-e为是否为临时节点(即若创建者断连,则自动删除)。对应Java里面的方法为:
String slaveNodeNameActulPath = zooKeeper.create("/slave/slave", "".getBytes(), OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
上述的创建中:
第一个参数为path,
第二个参数为value,
第三个参数为acl,即安全模式
第四个参数为创建的形式,.EPHEMERAL_SEQUENTIAL即对应上述的 -s ,-e 都有,即顺序的,临时的节点。
三、get 查看节点数据:
可以用zooKeeper的:
public void getData(final String path, Watcher watcher,
DataCallback cb, Object ctx)
方法,其中:
第一个参数为 节点 的path
第二个参数为监听的回调watcher(意为如果节点的data有更新,那么会回调这个方法,不过坑爹的是,这个方法只会回调一次,所以需要每次掉完之后再重新调用,具体解决方法我下面会说)
第三个参数为此次获取的数据回调,也就是会马上回调。
第四个参数为一个预留参数,如果传入进去了,那么在DataCallback的回调里面,会再传入进来。
1、
先讲第三个参数回调 DataCallback 吧,这个回调是在调用getData的时候马上回调的,也就是马上会把节点里面的数据传入进来:
processResult(int rc, String path, Object ctx, byte data[],Stat stat)
第一个rc即为这次操作的结果,0为成功,对应的枚举为:
org.apache.zookeeper.KeeperException.Code。
第二个path即为这个getData的path。
第三个ctx即为getData中传入的第四个参数
第四个data[]即为这个节点的内容(注意节点存的都是比特数组)
第五个stat即为节点的节点信息。
2、再说一下第二个参数回调 Watcher,这个是当节点内容有改动的时候,会调用的:
process(WatchedEvent event);
其中event里面包含了很多信息,包括这次回调的原因,为
event.getType()
因为我们只想查看因为数据更新而引起的回调,所以判断为:
if (Watcher.Event.EventType.NodeDataChanged != e.getType()) {
return;
}
还有,因为这个数据更新只会回调一次,所以我这样通过递归的方式调用,就能一直收到回调:
/**
* 循环监听Get的方法
* @param zooKeeper
* @param path
* @param watcher
* @param cb
* @param ctx
*/
public static void loopGet(ZooKeeper zooKeeper, final String path, Watcher watcher,
AsyncCallback.DataCallback cb, Object ctx) {
zooKeeper.getData(path, event -> {
if (watcher != null) {
watcher.process(event);
}
loopGet(zooKeeper, path, watcher, cb, ctx);
}, cb, ctx);
}
四、ls,ls2 查看节点的子节点:
获取子节点与监听子节点,可以使用zooKeeper的
public List<String> getChildren(final String path, Watcher watcher,Stat stat)
方法。
1、 其中返回的 List<String> 即为子节点的节点名(注意不是完全路径哦)
比如 /job 中有 "job000000000"、"job0000000001" 两个节点,那么List<String>获取的即是
"job000000000" 与 "job0000000001" 2、path即为想要获取的节点的path。
3、watcher即为对应回调接口
注意对应watcher中要增加判断:
private class JobWatcher implements Watcher{
@Override
public void process(WatchedEvent event) {
if (Watcher.Event.EventType.NodeChildrenChanged != event.getType()) {
// 非节点更新,返回
return;
}
// code ...
}
}
4、节点的节点信息stat,注意这个stat我们传入进去之后,zooKeeper会将此节点的信息设置进去,具体可以看源码:
if (stat != null) {
DataTree.copyStat(response.getStat(), stat);
}
static public void copyStat(Stat from, Stat to) {
to.setAversion(from.getAversion());
to.setCtime(from.getCtime());
to.setCversion(from.getCversion());
to.setCzxid(from.getCzxid());
to.setMtime(from.getMtime());
to.setMzxid(from.getMzxid());
to.setPzxid(from.getPzxid());
to.setVersion(from.getVersion());
to.setEphemeralOwner(from.getEphemeralOwner());
to.setDataLength(from.getDataLength());
to.setNumChildren(from.getNumChildren());
}
所以可以根据这个来获取对应节点的stat信息。
五、stat 查看节点信息:
可以使用zooKeeper的这个方法:
public Stat statNode(String path, Watcher watcher)
throws KeeperException.NoNodeException
六、set 设置节点数据:
可以使用zooKeeper的
public Stat setData(final String path, byte data[], int version)
方法。
其中
1、path即为要修改的节点的path
2、data即为要设置节点的数据字节数组
3、即为指定的version,如果version大于-1,那么只有当指定节点处于此version的时候,才会被更新,如果为-1,则不管version是多少,都会更新
(注意节点在创建的时候version为0,以后每次更新version都会+1)
返回值即为Stat,里面有节点的节点信息,比如version,如果设置了一个version为0的节点,那么返回的Stat中的version即为1(因为更新过了)
七、delete 删除节点:
删除可以使用
public void delete(final String path, int version)
方法
其中
path即为要删除的节点的path。
version即为指定的version,跟set一样,当version大于-1的时候,就会只删除指定的version,当version为-1的时候,就会直接删除。
此方法没有返回值。
八、分布式作业调度系统:
下一篇中,将会讲解使用ZooKeeper来实现一个分布式作业调度系统的原理,链接为 ZooKeeper完全解析(四) 使用ZooKeeper实现分布式作业调度系统之实现原理