zookeeper watch机制核心讲解

概述

zookeepere有watch事件,是一次性触发的,当watch监视的数据发生变化时,通知设置了该watch的client,即watcher。
同样,其watcher是监听数据发送了某些变化,那就一定会有对应的事件类型,和状态类型。
事件类型:(znode节点相关的)
EventType.NodeCreated
EventType.NodeDataChanged
EventType.NodeChildrenChanged
EventType.NodeDeleted

状态类型:(是跟客户端实例相关的)
KeeperState.Disconnected
KeeperState.SyncConnected
KeeperState.AuthFailed
KeeperState.Expired

代码:

package bhz.zookeeper.watcher;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
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;
/**
* Zookeeper Wathcher
* 本类就是一个Watcher类(实现了org.apache.zookeeper.Watcher类)
* @author(alienware)
* @since 2015-6-14
*/
public class ZooKeeperWatcher implements Watcher {
     /** 定义原子变量  初始值为0 后期使用incrementAndGet 每次加1*/
     AtomicInteger seq = new AtomicInteger();
     /** 定义session失效时间 */
     private static final int SESSION_TIMEOUT = 10000;
     /** zookeeper服务器地址 */
     private static final String CONNECTION_ADDR =  "192.168.0.71:2181,192.168.0.72:2181,192.168.0.73:2181";
     /** zk父路径设置 */
     private static final String PARENT_PATH = "/p";
     /** zk子路径设置 */
     private static final String CHILDREN_PATH = "/p/c";
     /** 进入标识 */
     private static final String LOG_PREFIX_OF_MAIN = "【Main】";
     /** zk变量 */
     private ZooKeeper zk = null;
     /**用于等待zookeeper连接建立之后 通知阻塞程序继续向下执行 */
     private CountDownLatch connectedSemaphore = new  CountDownLatch(1);
     /**
      * 创建ZK连接
      * @param connectAddr ZK服务器地址列表
      * @param sessionTimeout Session超时时间
      */
     public void createConnection(String connectAddr, int  sessionTimeout) {
           this.releaseConnection();
           try {
                //this表示把当前对象进行传递到其中去(也就是在主函数里实例化的new ZooKeeperWatcher()实例对象)
                zk = new ZooKeeper(connectAddr, sessionTimeout,  this);
                System.out.println(LOG_PREFIX_OF_MAIN + "开始连接ZK服务器");
                connectedSemaphore.await();
           } catch (Exception e) {
                e.printStackTrace();
           }
     }
     /**
      * 关闭ZK连接
      */
     public void releaseConnection() {
           if (this.zk != null) {
                try {
                      this.zk.close();
                } catch (InterruptedException e) {
                      e.printStackTrace();
                }
           }
     }
     /**
      * 创建节点
      * @param path 节点路径
      * @param data 数据内容
      * @return
      */
     public boolean createPath(String path, String data, boolean  needWatch) {
           try {
                //设置监控(由于zookeeper的监控都是一次性的所以 每次必须设置监控)
                //这里的needWatch 为boolean 类型 如果为true 则表明使用使用上下文中的watcher 即在main方法中创建的watcher
                this.zk.exists(path, needWatch);  
                System.out.println(LOG_PREFIX_OF_MAIN + "节点创建成功, Path: " +
                                         this.zk.create(    /**路径*/
                                                                  path,
                                                                  /**数据*/
                                                                  data.getBytes(),
                                                                  /**所有可见*/
                                                                  Ids.OPEN_ACL_UNSAFE,
                                                                  /**永久存储*/
                                                                  CreateMode.PERSISTENT ) +  
                                         ", content: " + data);
           } catch (Exception e) {
                e.printStackTrace();
                return false;
           }
           return true;
     }
     /**
      * 读取指定节点数据内容
      * @param path 节点路径
      * @return
      */
     public String readData(String path, boolean needWatch) {
           try {
                System.out.println("读取数据操作...");
                return new String(this.zk.getData(path,  needWatch, null));
           } catch (Exception e) {
                e.printStackTrace();
                return "";
           }
     }
     /**
      * 更新指定节点数据内容
      * @param path 节点路径
      * @param data 数据内容
      * @return
      */
     public boolean writeData(String path, String data) {
           try {
                System.out.println(LOG_PREFIX_OF_MAIN + "更新数据成功,path:" + path + ", stat: " +
                                            this.zk.setData(path,  data.getBytes(), -1));
           } catch (Exception e) {
                e.printStackTrace();
                return false;
           }
           return true;
     }
     /**
      * 删除指定节点
      *
      * @param path
      *            节点path
      */
     public void deleteNode(String path) {
           try {
                this.zk.delete(path, -1);
                System.out.println(LOG_PREFIX_OF_MAIN + "删除节点成功,path:" + path);
           } catch (Exception e) {
                e.printStackTrace();
           }
     }
     /**
      * 判断指定节点是否存在
      * @param path 节点路径
      */
     public Stat exists(String path, boolean needWatch) {
           try {
                return this.zk.exists(path, needWatch);
           } catch (Exception e) {
                e.printStackTrace();
                return null;
           }
     }
     /**
      * 获取子节点
      * @param path 节点路径
      */
     private List<String> getChildren(String path, boolean  needWatch) {
           try {
                System.out.println("读取子节点操作...");
                return this.zk.getChildren(path, needWatch);
           } catch (Exception e) {
                e.printStackTrace();
                return null;
           }
     }
     /**
      * 删除所有节点
      */
     public void deleteAllTestPath(boolean needWatch) {
           if(this.exists(CHILDREN_PATH, needWatch) != null){
                this.deleteNode(CHILDREN_PATH);
           }
           if(this.exists(PARENT_PATH, needWatch) != null){
                this.deleteNode(PARENT_PATH);
           }          
     }
     
     /**
      * 收到来自Server的Watcher通知后的处理。
      */
     @Override
     public void process(WatchedEvent event) {
           
           System.out.println("进入 process 。。。。。event = " +  event);
           
           try {
                Thread.sleep(200);
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
           
           if (event == null) {
                return;
           }
           
           // 连接状态
           KeeperState keeperState = event.getState();
           // 事件类型
           EventType eventType = event.getType();
           // 受影响的path
           String path = event.getPath();
           //原子对象seq 记录进入process的次数
           String logPrefix = "【Watcher-" +  this.seq.incrementAndGet() + "】";
           System.out.println(logPrefix + "收到Watcher通知");
           System.out.println(logPrefix + "连接状态:\t" +  keeperState.toString());
           System.out.println(logPrefix + "事件类型:\t" +  eventType.toString());
           if (KeeperState.SyncConnected == keeperState) {
                // 成功连接上ZK服务器
                if (EventType.None == eventType) {
                      System.out.println(logPrefix + "成功连接上ZK服务器");
                      connectedSemaphore.countDown();
                }
                //创建节点
                else if (EventType.NodeCreated == eventType) {
                      System.out.println(logPrefix + "节点创建");
                      try {
                           Thread.sleep(100);
                      } catch (InterruptedException e) {
                           e.printStackTrace();
                      }
                }
                //更新节点
                else if (EventType.NodeDataChanged == eventType)  {
                      System.out.println(logPrefix + "节点数据更新");
                      try {
                           Thread.sleep(100);
                      } catch (InterruptedException e) {
                           e.printStackTrace();
                      }
                }
                //更新子节点
                else if (EventType.NodeChildrenChanged ==  eventType) {
                      System.out.println(logPrefix + "子节点变更");
                      try {
                           Thread.sleep(3000);
                      } catch (InterruptedException e) {
                           e.printStackTrace();
                      }
                }
                //删除节点
                else if (EventType.NodeDeleted == eventType) {
                      System.out.println(logPrefix + "节点 " +  path + " 被删除");
                }
                else ;
           }
           else if (KeeperState.Disconnected == keeperState) {
                System.out.println(logPrefix + "与ZK服务器断开连接");
           }
           else if (KeeperState.AuthFailed == keeperState) {
                System.out.println(logPrefix + "权限检查失败");
           }
           else if (KeeperState.Expired == keeperState) {
                System.out.println(logPrefix + "会话失效");
           }
           else ;
           System.out.println("--------------------------------------------");
     }
     /**
      * <B>方法名称:</B>测试zookeeper监控<BR>
      * <B>概要说明:</B>主要测试watch功能<BR>
      * @param args
      * @throws Exception
      */
     public static void main(String[] args) throws Exception {
           //建立watcher //当前客户端可以称为一个watcher 观察者角色
           ZooKeeperWatcher zkWatch = new ZooKeeperWatcher();
           //创建连接
           zkWatch.createConnection(CONNECTION_ADDR,  SESSION_TIMEOUT);
           //System.out.println(zkWatch.zk.toString());
           
           Thread.sleep(1000);
           
           // 清理节点
           zkWatch.deleteAllTestPath(false);
           
           //-----------------第一步: 创建父节点 /p  ------------------------//
           if (zkWatch.createPath(PARENT_PATH,  System.currentTimeMillis() + "", true)) {
                
                Thread.sleep(1000);
                
                //-----------------第二步: 读取节点 /p 和    读取/p节点下的子节点(getChildren)的区别 --------------//
                // 读取数据
                zkWatch.readData(PARENT_PATH, true);
           
                // 读取子节点(监控childNodeChange事件)
                zkWatch.getChildren(PARENT_PATH, true);
                // 更新数据
                zkWatch.writeData(PARENT_PATH,  System.currentTimeMillis() + "");
                
                Thread.sleep(1000);
                // 创建子节点
                zkWatch.createPath(CHILDREN_PATH,  System.currentTimeMillis() + "", true);
                
                
                //-----------------第三步: 建立子节点的触发  --------------//
//              zkWatch.createPath(CHILDREN_PATH + "/c1",  System.currentTimeMillis() + "", true);
//              zkWatch.createPath(CHILDREN_PATH + "/c1/c2",  System.currentTimeMillis() + "", true);
                
                //-----------------第四步: 更新子节点数据的触发  --------------//
                //在进行修改之前,我们需要watch一下这个节点:
                Thread.sleep(1000);
                zkWatch.readData(CHILDREN_PATH, true);
                zkWatch.writeData(CHILDREN_PATH,  System.currentTimeMillis() + "");
                
           }
           
           Thread.sleep(10000);
           // 清理节点
           zkWatch.deleteAllTestPath(false);
           
           
           Thread.sleep(10000);
           zkWatch.releaseConnection();
           
     }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值