Zookeeper Java API
概述
- Zookeeper提供了Java API方便我们来操作zk服务,可以通过maven引入zk的相关依赖包。
- 通过org.apache.zookeeper.Zookeeper类创建连接zk服务器的示例对象,在创建过程中给定zk服务器地址、会话持续时间以及监视器三个参数,当连接创建成功后,通过Zookeeper实例提供的接口(或方法)来和服务器进行交互。
- Pom.xml文件依赖内容如下:
<dependencies> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.5</version> </dependency> </dependencies>
连接创建
使用Zookeeper类来表示连接,创建的该实例对象有四个构造方法来调用:
Zookeeper(connectString,sessionTimeout,watcher); ★//最常用 Zookeeper(connectString,sessionTimeout,watcher,canBeReadOnly);★//最常用 Zookeeper(connectString,sessionTimeout, watcher,sessionId,sessionPasswd) ; Zookeeper(connectString,sessionTimeout,watcher,sessionId,sessionPasswd,canBeReadOnly);
其中第一个构造方法底层调用第二个构造方法,只是canBeReadOnly参数设置为false。
参数说明:
1、connectString:参数为zk集群服务器的连接url,当给定路径的时候,表示所有的操作都是基于该路径进行操作的(路径只可以添加到最后)。
例如:”master.com:2181, master.com:2182, master.com:2183/app”。
2、sessionTimeout:为会话过期时间,以毫秒为单位,一般设置为tickTime的3-4倍;
客户端和服务器端之间的连接通过心跳包进行维系,如果心跳包超过这个指定时间则认为会话超时失效。一般设置为private static final int SESSION_TIMEOUT = 30000;
3、watcher:是监视器,用于触发相应事件,可以为空(表示不需要观察者);
4、canBeReadOnly:是否支持只读连接,默认为false。
5、sessionId、SessionPassword :会话编号 会话密码,用来实现会话恢复。
**注意1:整个创建会话的过程是异步的,构造方法会在初始化连接后即返回,并不代表真正建立好了一个会话,此时会话处于”CONNECTING”状态。
**注意2:当会话真正创建起来后,服务器会发送事件通知给客户端,只有客户端获取到这个通知后,会话才真正建立。
新增/创建节点
- ZK中新增子节点和创建节点其实是同一个含义,创建一个节点其实就相当于在根目录下新增一个子节点,
- 注意:zk不支持为不存在的父节点创建子节点(不支持循环创建)。
- 创建节点的时候要求指明节点被创建的类型(CreateMode)。
- 调用Zookeeper实例的create方法,需要给定的参数有:
//同步方式创建
String create(final String path,byte data[],List acl,CreateMode createMode);
说明:返回的是该节点的路径名称,例如:/test/zh_1324578
//异步方式创建【不常用】
void create(final String path,byte data[],List acl,CreateMode createMode,StringCallback cb,Object ctx);
说明:此创建方式是通过回调函数来相应操作。
参数说明:
1. path——要创建的数据节点的路径
2. data []——节点创建时初始数据内容
3. acl——节点acl安全策略,不考虑权限的情况下给定:ids.OPEN_ACL_UNSAFE。
4. createMode——创建模式
CreateMode类型 名称 详解 PERSISTENT 持久 会话结束后不会被自动删除 PERSISTENT_SEQUENTIAL 持久顺序 在节点名称后添加一个序列号(单调递增),不会自动删除 EPHEMERAL 临时 在会话结束后自动被删除 EPHEMERAL_SEQUENTIAL 临时顺序 在会话被结束后自动删除,会在给定的path节点名称后添加一个序列号(单调递增) 5. cb——回调接口
6. ctx——传递对象,用来在回调方法中使用 通常是个上下文对象
**注意:不支持递归创建,即不能在无父节点的情况下创建出子节点,尝试创建已经存在的节点将失败并抛出异常,在不需要进行任何权限控制时,只需传入Ids.OPEN_ACL_UNSAFE即可。
删除节点
当系统不需要某个配置节点的时候,或者某个节点失效的时候,使用delete方法可以删除该节点;
**注意:无法删除存在子节点的节点,即如果要删除一个节点,必须要先删除其所有子节点【不支持递归删除】
删除要求:被删除的节点木有子节点,并且需要给定明确的版本号(可以给定-1,表示不管版本号是什么都删除)
例如:
client.delete("/root/child", -1);//不管版本号直接删除
client.delete("/root", 0);//直接删除版本号为0的root节点,如果zk上root节点的版本是0,那么删除成功,否则抛出异常。
public void delete(final String path,int version)
说明:无返回类型
public void delete(final String path,int version,VoidCallback cb,Object ctx)
说明:无返回类型
获取子节点名称列表信息
//同步方式
List getChildren(final String path,Watcher watcher) List getChildren(String path,boolean watch) List getChildren(final String path,Watcher watcher,Stat stat) List getChildren(String path,boolean watch,Stat stat)
说明:上述返回的都是path路径下的节点名称
//异步方式
void getChildred(final String path,Watcher watcher,ChildrenCallback cb,Object ctx) void getChildred(String path,boolean watch,ChildrednCallback cb,Object ctx) void getChildred(final String path,Watcher watcher,Children2Callback cb,Object ctx) void getChildred(String path,boolean watch,Children2Callback cb,Object ctx)
参数说明
- path 要创建的数据节点的路径
- watcher 观察者,一旦在本子节点获取之后,子节点列表发生变更,服务器端向客户端发送消息,触发watcher中的回调。注意,仅仅是通知而已,如果需要新的子节点列表,需要自己再次去获取。允许传入null。
- watch 表明是否需要注册一个Watcher。为true则通知默认到默认watcher,如果为false则不使用
- cb 回掉函数
- ctx 上下文对象
- stat 指定数据节点的状态信息。用法是在接口中传入一个旧的stat变量,该stat变量会在方法执行过程中,被来自服务端响应的新stat对象替换。
获取节点数据
**注意:可以通过注册Watcher进行监听,一旦该节点数据被更新会通知客户端
例如:String data=new String(client.getData("/root/child", false, null));//获取数据,不进行wath机制监控,state状态信息为空
//同步方式
byte [] getData(final String path,Watcher watcher, Stat stat) byte [] getData(String path,boolean watch, Stat stat)
//异步方式
void getData(final String path,Watcher watcher, DataCallback cb,Object ctx) void getData(String path,boolean watch, DataCallback cb,Object ctx)
更新数据
当节点内容需要进行改变的时候可以调用setDate方法设置节点内容;
注意:设置节点内容时需要给定版本号,zk服务器会检查该版本号;
如果当前节点和你给定的版本号不一致,那么直接抛出异常,否则更新成功。
如果给定的版本号为-1,那么表示不检查。
例如:client.setData("/root/child", "new-data".getBytes(), -1);//设置新的内容
//同步方式
Stat setData(final String path,byte data[],int version) //version
说明:可以传入-1,表明要基于最新版本进行更新操作
//异步方式
void setData(final String path,byte data[],int version,StatCallback cb,Object ctx)
检查节点是否存在
**注意:可以通过注册Watcher进行监听,一旦节点被创建、删除、数据被更新都会通知客户端
//同步方式
public Stat exists(final String path,Watcher watcher) public Stat exists(String path,boolean watch)
//异步方式
public Stat exists(final String path,Watcher watcher,StatCallback cb,Object ctx) public Stat exists(String path,boolean watch,StatCallback cb,Object ctx)
其他方法
- addAuthInfo:添加权限验证scheme 信息
- getACL:获取节点的权限列表
- setACL:设置节点的权限列表
- getState:获取当前连接的States 信息
代码案例
创建节点
package com.master.zookeeper; import java.io.IOException; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; public class DemoCreate { public static String Url_1 = "192.168.1.111,192.168.1.111:2182,192.168.1.111:2183";// 端口号不一定,随意选择 public static String Url_2 = "192.168.1.111,192.168.1.111:2182,192.168.1.111:2183/app";// 端口号不一定,随意选择,给定路径 public static void main(String[] args) { // test1(); // test2(); } /** * 测试创建连接的时候给定路径 * @throws IOException * @throws KeeperException * @throws InterruptedException */ static void test2() throws IOException, KeeperException, InterruptedException { ZooKeeper client = new ZooKeeper(Url_2, 2000, new Watcher() { @Override public void process(WatchedEvent arg0) { } }); // 创建永久节点 String result = client.create("/root", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("创建永久节点/root结果:" + result); // 添加子节点——永久顺序节点 result = client.create("/root/child", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); System.out.println("添加节点/root/child结果:" + result); // 创建临时节点 result = client.create("/tmp", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); System.out.println("创建临时节点/root结果:" + result); // 创建临时顺序节点 result = client.create("/tmp", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println("创建临时顺序节点/root结果:" + result); Thread.sleep(10000); // 关闭会话 client.close(); } static void test1() throws IOException, KeeperException, InterruptedException { ZooKeeper client = new ZooKeeper(Url_1, 2000, new Watcher() { @Override public void process(WatchedEvent arg0) { } }); // 创建永久节点 String result = client.create("/root", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); System.out.println("创建永久节点/root结果:" + result); // 添加子节点——永久顺序节点 result = client.create("/root/child", "child".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); System.out.println("添加节点/root/child结果:" + result); // 创建临时节点 result = client.create("/tmp", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); System.out.println("创建临时节点/root结果:" + result); // 创建临时顺序节点 result = client.create("/tmp", "".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); System.out.println("创建临时顺序节点/root结果:" + result); Thread.sleep(5000); // 关闭会话 client.close(); } }
删除节点
package com.master.zookeeper; import java.io.IOException; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; public class DemoDelete { public static String Url_1 = "192.168.1.111,192.168.1.111:2182,192.168.1.111:2183";// 端口号不一定,随意选择 public static String Url_2 = "192.168.1.111,192.168.1.111:2182,192.168.1.111:2183/app";// 端口号不一定,随意选择,给定路径 public static void main(String[] args) { } static void test1() throws IOException, InterruptedException, KeeperException{ ZooKeeper client = new ZooKeeper(Url_1, 2000, new Watcher() { @Override public void process(WatchedEvent arg0) { } }); //删除节点 /root/child client.delete("/root/child", -1); //给定具体的版本号进行删除root client.delete("/root", client.exists("/root", false).getVersion()); //删除文件夹——递归删除 client.delete("/app", -1);//不支持递归删除 client.close(); } }
设置获取节点数据
package com.master.zookeeper; import java.io.IOException; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; /** * 演示设置数据和读取数据 * * @author Administrator * */ public class DemoData { public static String Url_1 = "192.168.1.111,192.168.1.111:2182,192.168.1.111:2183";// 端口号不一定,随意选择 public static String Url_2 = "192.168.1.111,192.168.1.111:2182,192.168.1.111:2183/app";// 端口号不一定,随意选择,给定路径 public static void main(String[] args) { } static void test1() throws IOException, InterruptedException, KeeperException { ZooKeeper client = new ZooKeeper(Url_1, 2000, new Watcher() { @Override public void process(WatchedEvent arg0) { } }); String data = ""; // 获取数据 // 第一种方式:当第二个参数为true的时候,会使用创建client时候给定的watcher实例进行监控 data = new String(client.getData("/root/child", false, null)); // 第二种方式:采用给定的监视器进行监控 // data = new String(client.getData("/root/child", new Watcher() { // @Override // public void process(WatchedEvent arg0) { // } // }, null)); // 设置数据 client.setData("/root/child", "new-data".getBytes(), -1); // 再重新获取数据 data = new String(client.getData("/root/child", new Watcher() { @Override public void process(WatchedEvent arg0) { } }, null)); client.close(); } }