简介
ZKClient是一个Zookeeper客户端框架,是对Zookeeper原生API的封装。使得使用更方便、功能更多。
查看之前必须要对Zookeeper的基本命令操作、Watch机制、Acl等有一定了解。
查看前必须要对原生API的基本使用有一定了解。
依赖:
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
ZkClient对Zookeeper的操作主要操作是通过org.I0Itec.zkclient.ZkClient类实现。
api:
//创建ZKClient客户端的构造器
//创建客户端并连接,参数是Zookeeper服务器的地址,与原生客户端的地址字符串一样,集群用逗号隔开。
public ZkClient(String serverstring)
/**
*创建客户端并连接
*zkServers Zookeeper服务器的地址
* connectionTimeout 设置连接超时,如果在设置时间内没能连接成功,就抛出异常。默认int类型最大值,单位毫秒。
**/
public ZkClient(String zkServers, int connectionTimeout)
/**
*创建客户端并连接
*zkServers Zookeeper服务器的地址
* sessionTimeout session超时,与原生客户端的作用一样。
* connectionTimeout 设置连接超时,如果在设置时间内没能连接成功,就抛出异常。默认int类型最大值,单位毫秒。
**/
public ZkClient(String zkServers, int sessionTimeout, int connectionTimeout)
/**
*创建客户端并连接
*zkServers Zookeeper服务器的地址
* sessionTimeout session超时,与原生客户端的作用一样。
* connectionTimeout 设置连接超时,如果在设置时间内没能连接成功,就抛出异常。默认int类型最大值,单位毫秒。
* ZkSerializer 自定义的序列化和反序列化器,默认使用java的对象序列化机制。
**/
public ZkClient(String zkServers, int sessionTimeout, int connectionTimeout, ZkSerializer zkSerializer)
//创建节点的API
/**
*创建持久化节点
*path:节点路径
*没有设置节点数据data,数据时对象null。
*/
public void createPersistent(String path)
/**
*创建持久化节点
*path:节点路径
*没有设置节点数据data,数据时对象null。
*createParents :是否递归创建父节点,true表示递归创建。
*/
public void createPersistent(String path, boolean createParents)
/**
*创建持久化节点
*path:节点路径
*没有设置节点数据data,数据时对象null。
*createParents :是否递归创建父节点,true表示递归创建。
* acl 指定特定的权限
*/
public void createPersistent(String path, boolean createParents, List<ACL> acl)
/**
*创建持久化节点,因为这里是专门有设置数据的,所以就不能递归创建多个节点。
*path:节点路径
*data:数据,如果创建ZKclient客户端时,没有指定序列化器,就会使用Java的对象序列化机制,
*也就是说如果没有指定序列化器,该data对象就必须实现。否则就会抛出java.io.NotSerializableException异常。
*/
public void createPersistent(String path, Object data)
/**
*创建持久化节点,因为这里是专门有设置数据的,所以就不能递归创建多个节点。
*path:节点路径
*data:数据,如果创建ZKclient客户端时,没有指定序列化器,就会使用Java的对象序列化机制,
*也就是说如果没有指定序列化器,该data对象就必须实现。否则就会抛出java.io.NotSerializableException异常。
* acl 指定特定的权限
*/
public void createPersistent(String path, Object data, List<ACL> acl)
/**
*创建临时节点
*path:节点路径
*没有设置节点数据data,数据时对象null。
*/
public void createEphemeral(String path)
/**
*创建临时节点
*path:节点路径
*没有设置节点数据data,数据时对象null。
*acl 指定特定的权限
*/
public void createEphemeral(String path, List<ACL> acl)
/**
*创建临时节点
*path:节点路径
*data 设置节点数据data。
*/
public void createEphemeral(String path, Object data)
/**
*创建临时节点
*path:节点路径
*data 设置节点数据data。
*acl 指定特定的权限
*/
public void createEphemeral(String path, Object data, List<ACL> acl)
/**
*创建持久化有序节点
*path 节点路径
*data 节点数据
* 返回值 String 创建的节点路径名,因为有序节点会在路径后面补后缀,所以要返回让我们知道实际的节点路径。
*/
public String createPersistentSequential(String path, Object data)
/**
*创建持久化有序节点
*path 节点路径
*data 节点数据
*acl 设置特定权限
* 返回值 String 创建的节点路径名,因为有序节点会在路径后面补后缀,所以要返回让我们知道实际的节点路径。
*/
public String createPersistentSequential(String path, Object data, List<ACL> acl)
/**
* 创建临时有序节点
*path 节点路径
*data 节点数据
* 返回值 String 创建的节点路径名,因为有序节点会在路径后面补后缀,所以要返回让我们知道实际的节点路径。
*/
public String createEphemeralSequential(String path, Object data)
/**
* 创建临时有序节点
*path 节点路径
*data 节点数据
*acl 设置特定权限
* 返回值 String 创建的节点路径名,因为有序节点会在路径后面补后缀,所以要返回让我们知道实际的节点路径。
*/
public String createEphemeralSequential(String path, Object data, List<ACL> acl)
/**
* 修改节点数据
* path 节点路径
* data 节点数据
*
public void writeData(String path, Object object)
/**
* 修改节点数据
* path 节点路径
* datat节点数据
* expectedVersion 数据版本,乐观锁
*/
public void writeData(String path, Object datat, int expectedVersion)
/**
* 修改节点数据并修改后的节点元信息
* path 节点路径
* datat 节点数据
* expectedVersion 数据版本,乐观锁 -1 该参数无效
*/
public Stat writeDataReturnStat(final String path, Object datat, final int expectedVersion)
//删除节点
public boolean delete(String path)
//删除节点 version 节点数据版本 乐观锁
public boolean delete(final String path, final int version)
//递归删除节点。
public boolean deleteRecursive(String path)
//查看节点数据,泛型方法。返回的数据要经过序列化器进行反序列化得到。
public <T> T readData(String path)
/**
* 查看节点数据,泛型方法。返回的数据要经过序列化器进行反序列化得到。
* returnNullIfPathNotExists 如果节点不存在时是否返回null ,true时返回null,false直接抛异常
*/
public <T> T readData(String path, boolean returnNullIfPathNotExists)
/**
* 查看节点数据,泛型方法。返回的数据要经过序列化器进行反序列化得到。
* stat 把节点的元信息 赋值到该对象上。
*/
public <T> T readData(String path, Stat stat)
/**
* 设置节点权限。
*/
public void setAcl(final String path, final List<ACL> acl)
//获取节点的子节点
public List<String> getChildren(String path)
//添加授权,与原生API用法差不多
public void addAuthInfo(final String scheme, final byte[] auth)
//查看节点是否存在,true存在 false不存在。
public boolean exists(String path)
//关闭连接
public void close()
监听watch机制相关的API//
//ZkClient把监听事件API分成三类,监听子节点变化,监听节点数据变化,监听连接状态变化。
//zkClient的监听API本身便带有重复监听效果
/**
* 监听子节点变化
* path:监听节点
* listener 一个接口,我们要实现它来定义相关回调方法
*/
public List<String> subscribeChildChanges(String path, IZkChildListener listener)
/**
* 监听节点数据变化
* path:监听节点
* listener 一个接口,我们要实现它来定义相关回调方法
*/
public void subscribeDataChanges(String path, IZkDataListener listener)
/**
* 监听连接状态变化,也就是监听None类型
* listener 一个接口,我们要实现它来定义相关回调方法
*/
public void subscribeStateChanges(IZkStateListener listener)
/**
* 撤销该客户端的所有监听
*/
public void unsubscribeAll()
/**
* 撤销某节点的某个监听,子节点变化监听
* path 节点路径
* childListener 要撤销的监听器,此时参数不能跟上面的参数那样新建一个对象,那样没有意义,应该传入一个与上面的监听一样的对象 也就是 obj == obj2
*/
public void unsubscribeChildChanges(String path, IZkChildListener childListener)
/**
* 撤销某节点的某个节点数据变化监听
* path 节点路径
* dataListener 要撤销的监听器,此时参数不能跟上面的参数那样新建一个对象,那样没有意义,应该传入一个与上面的监听一样的对象 也就是 obj == obj2
*/
public void unsubscribeDataChanges(String path, IZkDataListener dataListener)
/**
* 撤销某个状态变化监听
* stateListener要撤销监听器,此时参数不能跟上面的参数那样新建一个对象,那样没有意义,应该传入一个与上面的监听一样的对象 也就是 obj == obj2
*/
public void unsubscribeStateChanges(IZkStateListener stateListener)
练习Demo
public class ZkClientDemo {
//Zookeeper服务器地址,集群的话多个用逗号分隔
private static final String SERVER_STRING = "192.168.18.137:2181";
//父级节点路径
private static final String PREFIX_PATH = "/zkclient";
//获取客户端连接
public static ZkClient getZkClient(){
ZkClient zkClient = new ZkClient(SERVER_STRING,30000);
System.out.println("连接成功");
return zkClient;
}
//创建持久化节点
@Test
public void createPersistentNode(){
ZkClient zkClient = getZkClient();
zkClient.createPersistent(PREFIX_PATH + "/node1");
zkClient.createPersistent(PREFIX_PATH + "/node2/node2.0",true);
zkClient.createPersistent(PREFIX_PATH + "/node3",false, ZooDefs.Ids.OPEN_ACL_UNSAFE);
zkClient.createPersistent(PREFIX_PATH + "/node4",new UserConfig("John",18));
zkClient.createPersistent(PREFIX_PATH + "/node5",new UserConfig("Mike",25), ZooDefs.Ids.OPEN_ACL_UNSAFE);
zkClient.close();
}
//创建临时节点
@Test
public void createEphemeralNode(){
UserConfig John = new UserConfig("John",56);
ZkClient zkClient = getZkClient();
zkClient.createEphemeral(PREFIX_PATH + "/node7");
zkClient.createEphemeral(PREFIX_PATH + "/node8", ZooDefs.Ids.OPEN_ACL_UNSAFE);
zkClient.createEphemeral(PREFIX_PATH + "/node9",John);
zkClient.createEphemeral(PREFIX_PATH + "/node10",John, ZooDefs.Ids.OPEN_ACL_UNSAFE);
zkClient.close();
}
//创建持久化有序节点
@Test
public void createPersistentSeqNode(){
UserConfig John = new UserConfig("John",56);
ZkClient zkClient = getZkClient();
String node1 = zkClient.createPersistentSequential(PREFIX_PATH + "/node8", John);
String node2 = zkClient.createPersistentSequential(PREFIX_PATH + "/node9", John, ZooDefs.Ids.OPEN_ACL_UNSAFE);
System.out.println(node1);
System.out.println(node2);
zkClient.close();
}
//创建临时有序节点节点
@Test
public void createEphemeralSeqNode(){
UserConfig John = new UserConfig("John",56);
ZkClient zkClient = getZkClient();
String node1 = zkClient.createEphemeralSequential(PREFIX_PATH + "/node10", John);
String node2 = zkClient.createEphemeralSequential(PREFIX_PATH + "/node11",John, ZooDefs.Ids.OPEN_ACL_UNSAFE);
System.out.println(node1);
System.out.println(node2);
zkClient.close();
}
//设置节点数据
@Test
public void setNodeData(){
UserConfig John = new UserConfig("John",56);
ZkClient zkClient = getZkClient();
zkClient.writeData(PREFIX_PATH + "/node10", John);
zkClient.writeData(PREFIX_PATH + "/node10", John,5);
zkClient.writeDataReturnStat(PREFIX_PATH + "/node10", John,5);
zkClient.close();
}
//删除节点
@Test
public void deleteNode(){
ZkClient zkClient = getZkClient();
zkClient.delete(PREFIX_PATH + "/node10");
zkClient.delete(PREFIX_PATH + "/node10",5);
zkClient.deleteRecursive(PREFIX_PATH + "/node2");
zkClient.close();
}
//获取节点数据
@Test
public void getNodeData(){
Stat stat = new Stat();
ZkClient zkClient = getZkClient();
UserConfig userConfig = zkClient.readData(PREFIX_PATH + "/node9");
UserConfig userConfig1 = zkClient.readData(PREFIX_PATH + "/node8",stat);
UserConfig userConfig2 = zkClient.readData(PREFIX_PATH + "/node7",true);
}
//设置节点权限
@Test
public void setNodeAcl(){
ZkClient zkClient = getZkClient();
zkClient.setAcl(PREFIX_PATH + "/node10", ZooDefs.Ids.OPEN_ACL_UNSAFE);
zkClient.close();
}
//获取节点的子节点
@Test
public void getNodeChildren(){
ZkClient zkClient = getZkClient();
List<String> children = zkClient.getChildren(PREFIX_PATH + "/node10");
zkClient.addAuthInfo("digest","admin:123456".getBytes());
zkClient.close();
}
//测试watch机制
@Test
public void nodeWatch(){
//创建子节点变化监听器
IZkChildListener childListener = new IZkChildListener() {
/**
*子节点变化事件回调方法
* @param s 节点路径
* @param list 变化后的子节点列表
* @throws Exception
*/
@Override
public void handleChildChange(String s, List<String> list) throws Exception {
System.out.println(s);
System.out.println(list);
}
};
//创建节点数据变化监听器
IZkDataListener dataListener = new IZkDataListener() {
/**
* 节点数据发生改变回调函数
* @param s 节点路径
* @param o 修改后的数据
* @throws Exception
*/
@Override
public void handleDataChange(String s, Object o) throws Exception {
System.out.println(s);
System.out.println(o);
}
/**
* 节点删除事件回调函数
* @param s
* @throws Exception
*/
@Override
public void handleDataDeleted(String s) throws Exception {
System.out.println(s);
}
};
ZkClient zkClient = getZkClient();
zkClient.subscribeChildChanges(PREFIX_PATH + "/node10",childListener);
zkClient.subscribeDataChanges(PREFIX_PATH + "/node10",dataListener);
//对象必须一致
zkClient.unsubscribeChildChanges(PREFIX_PATH + "/node10",childListener);
zkClient.unsubscribeDataChanges(PREFIX_PATH + "/node10",dataListener);
}
}