ZooKeeper之Java API

ZooKeeper作为一个分布式服务框架,本身使用Java编写,也对多种编程提供了API,这里记录一下通过java api来操作zookeeper.

创建ZooKeeper会话实例(连通zookeeper):

ZooKeeper客户端与服务器的连接过程是一个异步过程,也就是说在程序中,客户端代码在构造方法处理完初始化工作后会立即返回,大对数情况下此时并没有真正完成一个可用的会话连接,此时在会话的生命周期里处于"CONNECTION"状态。当该会话真正创建完毕后,ZooKeeper服务器会向会话对应的客户端发送一个事件通知以告知客户端,客户端只有在获取到这个通知后才算是真正的建立了一个会话连接.

package yzr.zk;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
/*
 * 一个最基本的ZooKeeper会话实例
 */
public class zookeeper_constructor_usage_simple implements Watcher {

	public  static CountDownLatch connectionedSemaphore=new CountDownLatch(1);
	/*
	 * (non-Javadoc)
	 * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatchedEvent)
	 * 处理来自ZooKeeper服务器的Watch通知事件
	 * 在收到服务器发来的 SyncConnected事件之后,解除主程序中在计数器CountDownLatch上的等待阻塞.
	 */
	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: "+event);
		if(KeeperState.SyncConnected==event.getState()){
			connectionedSemaphore.countDown();
		}
	}
	
}
package yzr.run;
import org.apache.zookeeper.ZooKeeper;
import yzr.zk.zookeeper_constructor_usage_simple;
public class app {

	public static void main(String[] args) throws Exception {
		zookeeper_constructor_usage_simple zksimple=new zookeeper_constructor_usage_simple();
		/*
		 * 异步初始化Zookeeper
		 */
		ZooKeeper zookeeper =new ZooKeeper("192.168.199.100:2181",5000,zksimple);
		System.out.println(zookeeper.getState());
		//等待阻塞
		zksimple.connectionedSemaphore.await();
		System.out.println("ZooKeeper会话连接建立完成!");
	}

}

备注:CountDownLatch对象会在count递减到0时停止阻塞,在初始化构造中函数中指定count默认起始值,并且每调用一次countDown()方法,count值会减1直至为0,在await()的地方就会停止阻塞,使用程序继续执行。


复用SessionId和SessionPassword的ZooKeeper会话实例

在创建了与zookeeper正常的会话之后,zookeeper底层中会包含有该会话的一个id和password,可以借助此两个参数复用已经创建的会话连接。在zookeeper的构造函数中传入这两个参数即可。

package yzr.zk;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.KeeperState;
/*
 * 复用SessionID和SessionPassWd的ZooKeeper会话实例
 */
public class zookeeper_constuctor_usage_with_sid_password implements Watcher {

	public  static CountDownLatch connectionedSemaphore=new CountDownLatch(1);
	/*
	 * (non-Javadoc)
	 * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatchedEvent)
	 * 处理来自ZooKeeper服务器的Watch通知事件
	 * 在收到服务器发来的 SyncConnected事件之后,解除主程序中在计数器CountDownLatch上的等待阻塞.
 	 */
	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: "+event);
		if(KeeperState.SyncConnected==event.getState()){
			connectionedSemaphore.countDown();
		}
	}
}
package yzr.run;

import org.apache.zookeeper.ZooKeeper;

import yzr.zk.zookeeper_constuctor_usage_with_sid_password;

public class app2 {

	public static void main(String[] args) throws Exception {
		zookeeper_constuctor_usage_with_sid_password zksimple=new zookeeper_constuctor_usage_with_sid_password();
		ZooKeeper zookeeper =new ZooKeeper("192.168.199.100:2181",5000,zksimple);
		zksimple.connectionedSemaphore.await();
		//会话ID
		long sessioniId=zookeeper.getSessionId();
		//会话密码
		byte[] pwd=zookeeper.getSessionPasswd();
		/*
		 * ZooKeeper的构造函数中允许传入SessionID和SessionPasswd,可用于复用会话,以维持之前会话的有效性.
		 */
		zookeeper =new ZooKeeper("",5000,zksimple,sessioniId,pwd);
		Thread.sleep(Integer.MAX_VALUE);
		
		
		
	}
}

创建zookeeper节点:zookeeper提供了同步和异步两种api来实现zookeeper节点的操作。

创建节点 无论是同步还是异步的方式,ZooKeeper都不支持递归创建,无法在父节点不存在的情况创建子节点,另外,如果有节点已经存在,创建同名的节点的时候会抛出NodeExistsException异常,ZooKeeper的节点内容只支持byte[]数组类型,ZooKeeper不负责序列化的工作,需要我们自行序列化数据.如果创建的节点不需要权限控制,只需要在acl参数中传入Ids.OPEN_ACL_UNSAFE即可

同步 api:

package yzr.run;

import java.io.IOException;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

import yzr.zk.zookeeper_constructor_usage_simple;

public class create {

	public static void main(String[] args) throws Exception {
		zookeeper_constructor_usage_simple zksimple = new zookeeper_constructor_usage_simple();
		/*
		 * ZooKeeper客户端与服务器的连接过程是一个异步过程,也就是说在程序中,构造方法会在处理完客户端初始化工作后会立即返回,
		 * 大对数情况下此时并没有真正完成一个可用的会话连接,在会话的生命周期里处于"CONNECTION"状态
		 * 当该会话真正创建完毕后,ZooKeeper服务器会向会话对应的客户端发送一个事件通知以告知客户端,客户端只有在获取到这个通知后,
		 * 才算是真正的建立了一个会话连接.
		 */
		ZooKeeper zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zksimple);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zksimple.connectionedSemaphore.await();

		
		
		//同步
		// 无权限控制的临时节点
		String path1 = zookeeper.create(
				"/zk-create-test",
				"test".getBytes(),
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL);
		System.out.println("成功创建了一个无权限控制的临时节点:" + path1);
		//无权限控制的临时顺序节点
		String path2 = zookeeper.create(
				"/zk-create-test",
				"test".getBytes(), 
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL_SEQUENTIAL);
		System.out.println("成功创建了一个无权限控制的临时顺序节点:" + path2);

	}

}

控制台消息:

log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
CONNECTING
接收到的监听事件为: WatchedEvent state:SyncConnected type:None path:null
成功创建了一个无权限控制的临时节点:/zk-create-test
成功创建了一个无权限控制的临时顺序节点:/zk-create-test0000000006

异步api:

package yzr.run;

import java.io.IOException;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

import yzr.zk.zookeeper_constructor_usage_simple;

public class AsynCreate {

	public static void main(String[] args) throws Exception {
		zookeeper_constructor_usage_simple zksimple = new zookeeper_constructor_usage_simple();
		/*
		 * ZooKeeper客户端与服务器的连接过程是一个异步过程,也就是说在程序中,构造方法会在处理完客户端初始化工作后会立即返回,
		 * 大对数情况下此时并没有真正完成一个可用的会话连接,在会话的生命周期里处于"CONNECTION"状态
		 * 当该会话真正创建完毕后,ZooKeeper服务器会向会话对应的客户端发送一个事件通知以告知客户端,客户端只有在获取到这个通知后,
		 * 才算是真正的建立了一个会话连接.
		 */
		ZooKeeper zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zksimple);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zksimple.connectionedSemaphore.await();

		
		//异步方式
		System.out.println("异步创建节点");
		//无权限控制的临时节点
		zookeeper.create(
				"/zk-create-test",
				"test".getBytes(), 
				Ids.OPEN_ACL_UNSAFE,
				CreateMode.EPHEMERAL,
				new IStringCallback(), 
				"context");
		//无权限控制的临时节点
		zookeeper.create(
				"/zk-create-test",
				"".getBytes(), 
				Ids.OPEN_ACL_UNSAFE,
				CreateMode.EPHEMERAL,
				new IStringCallback(), 
				"context");
		
		//无权限控制的临时顺序节点
		zookeeper.create(
				"/zk-create-test",
				"test".getBytes(), 
				Ids.OPEN_ACL_UNSAFE,
				CreateMode.EPHEMERAL_SEQUENTIAL,
				new IStringCallback(), 
				"context");
		
		//因为是异步创建,这里让程序不要那么快结束,然后就可以查看到异步创建节点的过程与结果
		Thread.sleep(5000);
	}

}

package yzr.run;

import org.apache.zookeeper.AsyncCallback.StringCallback;

public class IStringCallback implements StringCallback {

	@Override
	public void processResult(int rc, String path, Object ctx, String name) {
		/*
		 * rc:ResultCode,服务端的响应码,可以根据rc识别出API调用的结果,常见的响应码如下:
		 * 0:ok调用成
		 * -4:客户端与服务端连接已经断开
		 * -110:指定节点已经存在
		 * -112:会话已经过期
		 * 
		 * path:创建节点时传入的path值
		 * 
		 * ctx:创建节点时传入的ctx值
		 * 
		 * name:实际中在zooKeeper服务器上创建的节点路径名
		 */
		System.out.println("新建的节点路径结果是: [响应码数:"+rc+",指定的Path:"+path+",指定的ctx:"+ctx+",实际创建的路径名为:"+name+"]");
	}
	
}



控制台消息:

log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
CONNECTING
接收到的监听事件为: WatchedEvent state:SyncConnected type:None path:null
异步创建节点
新建的节点路径结果是: [响应码数:0,指定的Path:/zk-create-test,指定的ctx:context,实际创建的路径名为:/zk-create-test]
新建的节点路径结果是: [响应码数:-110,指定的Path:/zk-create-test,指定的ctx:context,实际创建的路径名为:null]
新建的节点路径结果是: [响应码数:0,指定的Path:/zk-create-test,指定的ctx:context,实际创建的路径名为:/zk-create-test0000000011]

备注:/zk-create-test0000000011顺序节点中会在后面加上一串数字,这一串是作为排序用的,由zookeeper自动生成。在同一路径下创建相同节点是会出现的异常的,会抛出一个节点已存在的异常,返回的响应码是-110,正常的响应码为0.另外,还有-4(ConnectionLoss)客户端和服务端连接已经断开。-112(Session Expired)会话过期。

AsyncCallback包含了StatCallback,DataCallback,ACLCallback,ChildrenCallback,Children2Callback,StringCallback和VoidCallback七种不同的回调接口

获取zookeeper子节点列表:

如果zookeeper客户端在获取到指定节点的子节点列表后,还需要订阅这个子节点列表的变化通知,可以通过注册一个Watcher来实现.当有子节点,被添加或者删除的时候,服务端就会向客户端发送一个NodeChildrenChanged类型的事件通知,在服务端发送给客户端的事件通知中,是不包含最新的节点列表的,客户端必须主动重新进去获取.

同步api:

package yzr.zk;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;

public class zookeeper_constructor_usage_watchnodechage implements Watcher {

	public  static CountDownLatch connectionedSemaphore=new CountDownLatch(1);
	/*
	 * (non-Javadoc)
	 * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatchedEvent)
	 * 处理来自ZooKeeper服务器的Watch通知事件
	 * 在收到服务器发来的 SyncConnected事件之后,解除主程序中在计数器CountDownLatch上的等待阻塞.
	 */
	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: "+event);
		if(KeeperState.SyncConnected==event.getState()){
			if(EventType.None==event.getType() && null ==event.getPath()){
				connectionedSemaphore.countDown();
			}
			else if (event.getType()==EventType.NodeChildrenChanged){
				//子节点发生变化
				try {
					System.out.println("\n重新加载子节点为:"+zookeeper.getChildren(event.getPath(),true));
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
		}
	}
	
	static ZooKeeper zookeeper=null;
	public static void main(String[] args) throws Exception {
		zookeeper_constructor_usage_watchnodechage zk = new zookeeper_constructor_usage_watchnodechage();
		/*
		 * ZooKeeper客户端与服务器的连接过程是一个异步过程,也就是说在程序中,构造方法会在处理完客户端初始化工作后会立即返回,
		 * 大对数情况下此时并没有真正完成一个可用的会话连接,在会话的生命周期里处于"CONNECTION"状态
		 * 当该会话真正创建完毕后,ZooKeeper服务器会向会话对应的客户端发送一个事件通知以告知客户端,客户端只有在获取到这个通知后,
		 * 才算是真正的建立了一个会话连接.
		 */
		zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zk);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zk.connectionedSemaphore.await();
		String path="/zk-test";
		zookeeper.create(
				path+"/t1",
				"t1".getBytes(),
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL);
		List<String> chlidren=zookeeper.getChildren(path, true);
		System.out.println("当前指定路径下的所有子节点为:"+chlidren);
		zookeeper.create(
				path+"/t2",
				"t2".getBytes(),
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL);
		zookeeper.create(
				path+"/t3",
				"t3".getBytes(),
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL);
		Thread.sleep(5000);
		
	}

}


控制台打印的消息:

log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
CONNECTING
接收到的监听事件为: WatchedEvent state:SyncConnected type:None path:null
当前指定路径下的所有子节点为:[t1]
接收到的监听事件为: WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/zk-test

重新加载子节点为:[t1, t2]
接收到的监听事件为: WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/zk-test

重新加载子节点为:[t1, t2, t3]
[ ResultCode:0,Path:/zk-test,ctx:context,children:[t1, t2, t3],stat12884901897,12884901897,1501070933318,1501070933318,0,31,0,0,3,3,17179869189
]

异步api:

package yzr.zk;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;

import yzr.run.IChildren2Callback;

import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;

public class zookeeper_constructor_usage_watchnodechage implements Watcher {

	public  static CountDownLatch connectionedSemaphore=new CountDownLatch(1);
	/*
	 * (non-Javadoc)
	 * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatchedEvent)
	 * 处理来自ZooKeeper服务器的Watch通知事件
	 * 在收到服务器发来的 SyncConnected事件之后,解除主程序中在计数器CountDownLatch上的等待阻塞.
	 */
	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: "+event);
		if(KeeperState.SyncConnected==event.getState()){
			if(EventType.None==event.getType() && null ==event.getPath()){
				connectionedSemaphore.countDown();
			}
			else if (event.getType()==EventType.NodeChildrenChanged){
				//子节点发生变化
				try {
					System.out.println("\n重新加载子节点为:"+zookeeper.getChildren(event.getPath(),true));
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
		}
	}
	
	static ZooKeeper zookeeper=null;
	public static void main(String[] args) throws Exception {
		zookeeper_constructor_usage_watchnodechage zk = new zookeeper_constructor_usage_watchnodechage();
		
		zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zk);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zk.connectionedSemaphore.await();
		String path="/zk-test";
		zookeeper.create(
				path+"/t1",
				"t1".getBytes(),
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL);
		List<String> chlidren=zookeeper.getChildren(path, true);
		System.out.println("当前指定路径下的所有子节点为:"+chlidren);
		zookeeper.create(
				path+"/t2",
				"t2".getBytes(),
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL);
		zookeeper.create(
				path+"/t3",
				"t3".getBytes(),
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL);
		
		
		zookeeper.getChildren(path,true,new IChildren2Callback(),"context");
		Thread.sleep(5000);
		
	}

}
package yzr.run;

import java.util.List;

import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.data.Stat;

public class IChildren2Callback implements AsyncCallback.Children2Callback {

	@Override
	public void processResult(int rc, String path, Object ctx, List<String> children, Stat stat) {
		
		System.out.println("[ ResultCode:"+rc+",Path:"+path+",ctx:"+ctx+",children:"+children+",stat"+stat+"]");
	}

}

控制台打印的消息:

log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
CONNECTING
接收到的监听事件为: WatchedEvent state:SyncConnected type:None path:null
当前指定路径下的所有子节点为:[t1]
接收到的监听事件为: WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/zk-test

重新加载子节点为:[t1, t2]
接收到的监听事件为: WatchedEvent state:SyncConnected type:NodeChildrenChanged path:/zk-test

重新加载子节点为:[t1, t2, t3]
[ ResultCode:0,Path:/zk-test,ctx:context,children:[t1, t2, t3],stat12884901897,12884901897,1501070933318,1501070933318,0,31,0,0,3,3,17179869189
]


更新zookeeper节点数据内容:

同理还是有同步和异步两种方式,不过需要指出一点的是version参数的用法,此参数是用于指定节点的数据版本,如果此参数的值大于-1,表明本次更新操作是针对指定的数据版本进行的。讲到这里可以先来看一下CAS理论:通俗的讲就是对于值V,每次更新之前都会比较其预想值,只有符合预期,才会将V进行更新。zookepper的setData的version参数正是由CAS原理衍生出来的。具体来说,假设一个客户端进行更新操作的时候,如果携带了version参数,这执行期间,如果zookeeper上该节点刚刚好已经被更新过,那么其数据版本肯定是发生变化而导致version更新,所以是无法与传递的version参数值匹配的,于是便无法更新成功。这就有效避免了分布式更新的并发问题。

同步api:

package yzr.zk;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;

public class zookeeper_setdata_api implements Watcher {

	public static CountDownLatch connectionedSemaphore = new CountDownLatch(1);
	private static Stat stat = new Stat();

	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: " + event);
		if (KeeperState.SyncConnected == event.getState()) {
			if (EventType.None == event.getType() && null == event.getPath()) {
				connectionedSemaphore.countDown();
			} else if (event.getType() == EventType.NodeDataChanged) {
				// 节点发生变化
				try {
					System.out.println("\n重新加载节点数据内容:" + new String(zookeeper.getData(event.getPath(), true, stat)));
					// 打印节点状态信息
					System.out.println(
							"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	static ZooKeeper zookeeper = null;

	public static void main(String[] args) throws Exception {
		System.out.println("-----------");
		zookeeper_setdata_api zk = new zookeeper_setdata_api();

		zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zk);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zk.connectionedSemaphore.await();
		String path = "/zk-test";
		zookeeper.create(path + "/t1", "content".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		byte[] content = zookeeper.getData(path+"/t1", true, stat);
		System.out.println("节点原始数据内容:" + new String(content));
		System.out.println(
				"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
		// 修改节点数据内容
		zookeeper.setData(path + "/t1", "new content".getBytes(), -1);
		Thread.sleep(Integer.MAX_VALUE);

	}

}

异步api:

package yzr.zk;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;

import yzr.run.IStatCallback;

public class zookeeper_setdata_api_async implements Watcher {

	public static CountDownLatch connectionedSemaphore = new CountDownLatch(1);
	private static Stat stat = new Stat();

	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: " + event);
		if (KeeperState.SyncConnected == event.getState()) {
			if (EventType.None == event.getType() && null == event.getPath()) {
				connectionedSemaphore.countDown();
			} else if (event.getType() == EventType.NodeDataChanged) {
				// 节点发生变化
				try {
					System.out.println("\n重新加载节点数据内容:" + new String(zookeeper.getData(event.getPath(), true, stat)));
					// 打印节点状态信息
					System.out.println(
							"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	static ZooKeeper zookeeper = null;

	public static void main(String[] args) throws Exception {
		System.out.println("-----------");
		zookeeper_setdata_api_async zk = new zookeeper_setdata_api_async();

		zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zk);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zk.connectionedSemaphore.await();
		String path = "/zk-test";
		zookeeper.create(path + "/t1", "content".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		byte[] content = zookeeper.getData(path+"/t1", true, stat);
		System.out.println("节点原始数据内容:" + new String(content));
		System.out.println(
				"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
		// 修改节点数据内容
		zookeeper.setData(path + "/t1", "new content".getBytes(), -1,new IStatCallback(),null);
		Thread.sleep(Integer.MAX_VALUE);

	}

}
package yzr.run;

import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.data.Stat;

public class IStatCallback implements StatCallback {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	@Override
	public void processResult(int rc, String path, Object ctx, Stat stat) {
		if(rc==0){
			System.out.println("success");
		}
		
	}

}

获取zookeeper节点值:

getData接口也是有同步和异步两种方式,客户端在获取某一zookeeper节点数据内容的时候,是可以进行Watcher注册的,一旦该注册过的节点发生状态变化,就没zookeeper服务端会触发一个NodeDataChanged事件通知客户端。

另外API返回的结果类型是byte[],需要自行序列化。

同步api:

package yzr.zk;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

/*
 * 获取节点数据内容
 */
public class zookeeper_getData_API implements Watcher {

	public static CountDownLatch connectionedSemaphore = new CountDownLatch(1);
	private static Stat stat = new Stat();

	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: " + event);
		if (KeeperState.SyncConnected == event.getState()) {
			if (EventType.None == event.getType() && null == event.getPath()) {
				connectionedSemaphore.countDown();
			} else if (event.getType() == EventType.NodeDataChanged) {
				// 节点发生变化
				try {
					System.out.println("\n重新加载节点数据内容:" + new String(zookeeper.getData(event.getPath(), true, stat)));
					// 打印节点状态信息
					System.out.println(
							"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	static ZooKeeper zookeeper = null;

	public static void main(String[] args) throws Exception {
		System.out.println("-----------");
		zookeeper_getData_API zk = new zookeeper_getData_API();

		zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zk);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zk.connectionedSemaphore.await();
		String path = "/zk-test";
		zookeeper.create(path + "/t1", "content".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		byte[] content = zookeeper.getData(path+"/t1", true, stat);
		System.out.println("节点原始数据内容:" + new String(content));
		System.out.println(
				"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
		// 修改节点数据内容
		zookeeper.setData(path + "/t1", "new content".getBytes(), -1);
		Thread.sleep(Integer.MAX_VALUE);

	}

}

异步api:

package yzr.zk;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;

import yzr.run.IDataCallBack;

/*
 * 获取节点数据内容
 */
public class zookeeper_getdata_async implements Watcher {

	public static CountDownLatch connectionedSemaphore = new CountDownLatch(1);
	private static Stat stat = new Stat();

	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: " + event);
		if (KeeperState.SyncConnected == event.getState()) {
			if (EventType.None == event.getType() && null == event.getPath()) {
				connectionedSemaphore.countDown();
			} else if (event.getType() == EventType.NodeDataChanged) {
				// 节点发生变化
				try {
					System.out.println("\n重新加载节点数据内容:");
					zookeeper.getData(event.getPath(), true, new IDataCallBack(),null);
					// 打印节点状态信息
					System.out.println(
							"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	static ZooKeeper zookeeper = null;

	public static void main(String[] args) throws Exception {
		System.out.println("-----------");
		zookeeper_getData_API zk = new zookeeper_getData_API();

		zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zk);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zk.connectionedSemaphore.await();
		String path = "/zk-test";
		zookeeper.create(path + "/t1", "content".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		zookeeper.getData(path+"/t1", true, new IDataCallBack(),null);
		
		System.out.println(
				"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
		// 修改节点数据内容
		zookeeper.setData(path + "/t1", "new content".getBytes(), -1);
		Thread.sleep(Integer.MAX_VALUE);

	}

}

package yzr.run;

import org.apache.zookeeper.AsyncCallback.DataCallback;
import org.apache.zookeeper.data.Stat;

public class IDataCallBack implements DataCallback {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

	@Override
	public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {
		System.out.println("[ ResultCode:"+rc+",Path:"+path+",ctx:"+ctx+",data:"+new String(data)+"]");
		System.out.println(
				"事务ID:" + stat.getCzxid() + "," + stat.getMzxid() + ",节点内容版本:" + stat.getVersion());
		
	}

}

控制台打印消息:

-----------
log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
CONNECTING
接收到的监听事件为: WatchedEvent state:SyncConnected type:None path:null
节点原始数据内容:content
事务ID:17179869211,17179869211,节点内容版本:0
接收到的监听事件为: WatchedEvent state:SyncConnected type:NodeDataChanged path:/zk-test/t1

重新加载节点数据内容:new content
事务ID:17179869211,17179869212,节点内容版本:1

检测节点是否存在:

返回值是一个stat对象,如果在调用时注册了watcher,那么对节点是否进行监听,一旦节点被创建,被修改和删除都会通知客户端。

package yzr.zk;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

import yzr.run.IChildren2Callback;

public class zookeeper_existes_api implements Watcher {

	public  static CountDownLatch connectionedSemaphore=new CountDownLatch(1);
	/*
	 * (non-Javadoc)
	 * @see org.apache.zookeeper.Watcher#process(org.apache.zookeeper.WatchedEvent)
	 * 处理来自ZooKeeper服务器的Watch通知事件
	 * 在收到服务器发来的 SyncConnected事件之后,解除主程序中在计数器CountDownLatch上的等待阻塞.
	 */
	@Override
	public void process(WatchedEvent event) {
		System.out.println("接收到的监听事件为: "+event);
		if(KeeperState.SyncConnected==event.getState()){
			if(EventType.None==event.getType() && null ==event.getPath()){
				connectionedSemaphore.countDown();
			}
			else if (event.getType()==EventType.NodeDataChanged){
				//子节点发生变化
				try {
					System.out.println("Node Data Changed:"+event.getPath());
					//重新注册
					zookeeper.exists(event.getPath(), true);
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
			else if (event.getType()==EventType.NodeCreated){
				//子节点发生变化
				try {
					System.out.println("Node Created:"+event.getPath());
					//重新注册
					zookeeper.exists(event.getPath(), true);
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
			else if (event.getType()==EventType.NodeDeleted){
				//子节点发生变化
				try {
					System.out.println("Node Deleted:"+event.getPath());
					//重新注册
					zookeeper.exists(event.getPath(), true);
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
		}
	}
	
	static ZooKeeper zookeeper=null;
	public static void main(String[] args) throws Exception {
		zookeeper_existes_api zk = new zookeeper_existes_api();
		/*
		 * ZooKeeper客户端与服务器的连接过程是一个异步过程,也就是说在程序中,构造方法会在处理完客户端初始化工作后会立即返回,
		 * 大对数情况下此时并没有真正完成一个可用的会话连接,在会话的生命周期里处于"CONNECTION"状态
		 * 当该会话真正创建完毕后,ZooKeeper服务器会向会话对应的客户端发送一个事件通知以告知客户端,客户端只有在获取到这个通知后,
		 * 才算是真正的建立了一个会话连接.
		 */
		zookeeper = new ZooKeeper("192.168.199.100:2181", 5000, zk);
		System.out.println(zookeeper.getState());
		// 等待阻塞
		zk.connectionedSemaphore.await();
		String path="/zk-test/t2";
		
		zookeeper.exists(path, true);
		
		zookeeper.create(
				path,
				"tttt".getBytes(),
				Ids.OPEN_ACL_UNSAFE, 
				CreateMode.EPHEMERAL);
		zookeeper.setData(path, "yyyy".getBytes(), -1);
		zookeeper.delete(path, -1);
		Thread.sleep(5000);
		
	}

}


打印消息:

log4j:WARN No appenders could be found for logger (org.apache.zookeeper.ZooKeeper).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
CONNECTING
接收到的监听事件为: WatchedEvent state:SyncConnected type:None path:null
接收到的监听事件为: WatchedEvent state:SyncConnected type:NodeCreated path:/zk-test/t2
Node Created:/zk-test/t2
接收到的监听事件为: WatchedEvent state:SyncConnected type:NodeDataChanged path:/zk-test/t2
Node Data Changed:/zk-test/t2
接收到的监听事件为: WatchedEvent state:SyncConnected type:NodeDeleted path:/zk-test/t2
Node Deleted:/zk-test/t2










  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值