本文学习资源来自《从Paxos到ZooKeeper分布式一致性原理与实践》
ZkClient
ZkClient 在ZooKeeper原生API接口之上进行了封装,是一个更易用的ZooKeeper客户端。同时,ZkClient在内部实现了诸如Session超时重连、Watcher反复注册等功能,使得ZooKeeper客户端的这些繁琐的细节工作对开发人员透明。
连接
package zookeeper;
import java.io.IOException;
import org.I0Itec.zkclient.ZkClient;
public class Create_Session_Sample {
public static void main(String[] args)throws IOException,InterruptedException{
ZkClient zkClient = new ZkClient("127.0.0.1:2181",5000);
System.out.println("ZooKeeper session established");
}
}
创建节点
ZkClient 中提供了以下一系列接口来创建节点,开发者可以通过这些接口来进行各种类型的节点创建:
String create(final String path,Object data,final CreateMode mode)
String create(final String path,Object dta,final List<ACL> acl,final CreateMode mode)
void create(final String path,Object data,final CreateMode mode,final AsyncCallback.StringCallback callback,final Object context)
void createEphemeral(final String path)
void createEphemeral(final String path,final Object data)
void createPersistent(String path);
void createPersistent(String path,boolean createParents);
void createPersistent(String path,Object data);
void createPersistent(String path,List<ACL> acl,Object data);
String createPersistentSequential(String path,Object data);
String createEphemeralSequential(final String path,final Object data);
ZkClient提供的接口,由于支持了自定义序列化器,因此可以传入复杂对象作为参数。
boolean createParents参数支持递归创建节点。
删除节点
在ZkClient中,可以通过以下API来删除指定节点:
boolean delete(final String path)
delete(final String path,final AsyncCallback.VoidCallback callback,final Object context);
boolean deleteRecursive(String path);
deleteRecursive支持自动逐层遍历删除节点。
读取结点
在ZkClient中,可以通过以下API来获取指定节点的子节点列表:
List<String> getChildren(String path)
ZkClient提供的API没有了Watcher注册的功能。ZkClient引入了Listener的概念,客户端可以通过注册相关的事件监听来实现对ZooKeeper服务端事件的订阅。在获取子节点列表这个接口上,可以通过如下API来进行注册监听:
List<String>subscribeChildChanges(String path,IZkChildListener listener)
通过该API的调用,就完成了事件监听的注册。该监听 是对子节点列表变更的监听,也就是说,一旦子节点列表发生变更,ZooKeeper服务端就会向客户端发出事件通知,由这个Listener来处理。
public interface IZkChildListener{
public void handleChildChange(String parentPath,List<String> currentChilds) throws Exception;
}
代码示例:
package zookeeper;
import java.util.List;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;
public class Get_Children_Sample {
public static void main(String[] args)throws Exception{
String path = "/zk-book";
ZkClient zkClient = new ZkClient("127.0.0.1:2181",5000);
zkClient.subscribeChildChanges(path,new IZkChildListener(){
@Override
public void handleChildChange(String parentPath, List<String> currentChilds)
throws Exception {
System.out.println(parentPath + " 's child changed,currentChilds:" + currentChilds);
}
});
zkClient.createPersistent(path);
Thread.sleep(1000);
System.out.println(zkClient.getChildren(path));
Thread.sleep(1000);
zkClient.createPersistent(path + "/c1");
Thread.sleep(1000);
zkClient.delete(path + "/c1");
Thread.sleep(1000);
zkClient.delete(path);
Thread.sleep(Integer.MAX_VALUE);
}
}
运行结果:
/zk-book 's child changed,currentChilds:[]
[]
/zk-book 's child changed,currentChilds:[c1]
/zk-book 's child changed,currentChilds:[]
/zk-book 's child changed,currentChilds:null
- 客户端可以对一个不存在的节点进行监听
- 一旦客户端对一个节点注册了子节点列表变更监听之后,那么当该节点的子节点列表发生变更的时候,服务端都会通知客户端,并将最新的子节点列表发送给客户端。
- 该节点本身的创建或删除也会通知到客户端。
另外与ZooKeeper原生的Watcher不同的是,ZkClient的Listener不是一次性的,客户端只需要注册一次就会一直生效。
读取数据
<T extends Object> T readData(String path)
<T extends Object> T readData(String path,boolean returnNullIfPathNotExists)
<T extends Object> T readData(String path,Stat stat)
该接口对服务端事件的监听,同样是通过注册指定的Listener来实现的。
public interface IZkDataListener{
public void handleDataChange(String dataPath,Object data) throws Exception;
public void handleDataDeleted(String dataPath) throws Exception;
}
示例代码:
package zookeeper;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
public class Get_Data_Sample {
public static void main(String[] args) throws Exception{
String path = "/zk-book";
ZkClient zkClient = new ZkClient("127.0.0.1:2181",5000);
zkClient.createEphemeral(path,"123");
zkClient.subscribeDataChanges(path,new IZkDataListener(){
@Override
public void handleDataChange(String dataPath, Object data) throws Exception {
System.out.println("Node " + dataPath + " changed,new data:." + data);
}
@Override
public void handleDataDeleted(String dataPath) throws Exception {
System.out.println("Node" + dataPath + " deleted");
}
});
System.out.println(zkClient.readData(path));
zkClient.writeData(path, "456");
Thread.sleep(1000);
zkClient.delete(path);
Thread.sleep(Integer.MAX_VALUE);
}
}
运行结果:
123
Node /zk-book changed,new data:.456
Node/zk-book deleted
更新数据
void writeData(String path,Object data);
void writeData(final String path,Object data,final int expectedVersion)
检测数据是否存在
boolean exists(final String path)