在ZooKeeper中,所有的同步调用命令,都会有一个相应的异步调用方法。异步调用能在一个单独线程中同时提交更多的命令,也能在一定程度上简化代码实现。
1 异步create方法
如创建zNode的命令create,同步方法的定义是
/** * @param path 创建节点的路径 * @param data 创建节点的初始值 * @param acl 创建节点的ACL * @param createMode 创建节点使用永久还是临时模式 * @return 创建节点的真实路径 * @throws KeeperException 服务器返回了非0的错误代码 * @throws KeeperException.InvalidACLException ACL非法或者为空 * @throws InterruptedException 事务被中断 * @throws IllegalArgumentException 路径非法 */ public String create(final String path, byte data[], List<ACL> acl, CreateMode createMode);
对应的异步调用方法
/** * create方法的异步调用方法 * @param path 创建节点的路径 * @param data 创建节点的初始值 * @param acl 创建节点的ACL * @param createMode 创建节点使用永久还是临时模式 * @param cb 包括回调函数的对象 * @param ctx 上下文对象(异步回调时会传递给callback,方便出错时重新调用) */ public void create(final String path, byte data[], List<ACL> acl, CreateMode createMode, StringCallback cb, Object ctx);
StringCallback的定义
interface StringCallback extends AsyncCallback { /** * 处理异步调用的结果 * @param rc 调用的返回码 * @param path 异步调用时的路径参数 * @param ctx 异步调用时的上下文对象 * @param name 实际创建的节点名 * 成功时通常同path相同,除非创建的是sequential节点 */ public void processResult(int rc, String path, Object ctx, String name); }
异步调用与同步调用的两个主要区别:
- 异步调用没有返回值(void)
- 异步调用不抛出异常,异常情况都通过rc参数传递
2 部分rc代码定义
回调函数的第一个参数 rc ,是调用的返回值。ZooKeeper在枚举org.apache.zookeeper.KeeperException.Code中做了定义。从源码中摘出一些我们可能会经常使用的Code
/** 一切安好 */ OK (Ok), /** 服务器连接丢失 */ CONNECTIONLOSS (ConnectionLoss), /** 操作超时 */ OPERATIONTIMEOUT (OperationTimeout), /** 参数错误 */ BADARGUMENTS (BadArguments), /** 节点不存在 */ NONODE (NoNode), /** 临时节点没有子节点 */ NOCHILDRENFOREPHEMERALS (NoChildrenForEphemerals), /** 节点已经存在 */ NODEEXISTS (NodeExists), /** 节点有子节点 */ NOTEMPTY (NotEmpty), /** 会话超时 */ SESSIONEXPIRED (SessionExpired), /** 请求超时*/ REQUESTTIMEOUT (-122),
3 回调函数的一般用法
下面是一个创建节点的简单例子。注意,ctx参数传递的是data,这个参数会直接传递到callback函数中,这样就可以直接重新调用create命令。
void createNode(String path, byte[] data) { zooKeeper.create(nodePath, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, nodeCreateCallback, data); } AsyncCallback.StringCallback nodeCreateCallback = new AsyncCallback.StringCallback() { public void processResult(int rc, String path, Object ctx, String name) { switch (KeeperException.Code.get(rc)) { case OK: // 创建节点成功 break; case CONNECTIONLOSS: // 连接丢失,重新发布命令 createNode(path, ctx); return; default: // 其他异常,抛出或记录异常 KeeperException e = KeeperException.create(KeeperException.Code.get(rc), path); log.error("create node error", e); } } };
4 异步回调接口定义
ZooKeeper在org.apache.zookeeper.AsyncCallback中定义了几个回调接口
回调接口 | 说明 | 适用的异步命令 |
StatCallback | 用于获取节点的状态 | void exists() void setData() |
DataCallback | 用于获取节点的值和状态 | void getData() void getConfig() |
ACLCallback | 用于获取节点的ACL信息和状态 | void getACL() |
ChildrenCallback | 用于获取节点的子节点列表 | void getChildren() |
Children2Callback | 用于获取节点的子节点列表和状态 | void getChildren() |
Create2Callback | 用于获取节点的名称和状态 | void create() |
StringCallback | 用于获取节点的名称 | void create() |
VoidCallback | 不返回任何信息 | void delete() void sync() void removeWatches() void removeAllWatches() |
MultiCallback | 用于多命令请求的返回值 | void multi() |
可以看到,有些异步命令,可以选择使用多个不同的Callback,见下表
异步命令 | 可选的回调接口 | 接口说明 |
void create() | Create2Callback | 用于获取节点的名称和状态 |
StringCallback | 用于获取节点的名称 | |
void getChildren() | ChildrenCallback | 用于获取节点的子节点列表 |
Children2Callback | 用于获取节点的子节点列表和状态 |