ZooKeeper Watch Java API浅析getData


原文:http://blog.csdn.net/lipeng_bigdata/article/details/50985811


Watch是ZooKeeper中非常重要的一个机制,它可以监控ZooKeeper中节点的变化情况,告知客户端。下面,我们以代码为例来分析Watch在ZooKeeper中是如何实现的。ZooKeeper中一共由三种方法可以实现Watch,分别为getData、exists和getChildren,今天我们先来看下getData()方法:

        1、getData()

  1. import java.io.IOException;  
  2.   
  3. import org.apache.zookeeper.CreateMode;  
  4. import org.apache.zookeeper.KeeperException;  
  5. import org.apache.zookeeper.WatchedEvent;  
  6. import org.apache.zookeeper.Watcher;  
  7. import org.apache.zookeeper.ZooKeeper;  
  8. import org.apache.zookeeper.ZooDefs.Ids;  
  9.   
  10. public class TestZooKeeperWatcher {  
  11.   
  12.     public static void main(String[] args) {  
  13.   
  14.         ZooKeeper zk = null;  
  15.         try {  
  16.   
  17.             System.out.println("...");  
  18.             System.out.println("...");  
  19.             System.out.println("...");  
  20.             System.out.println("...");  
  21.   
  22.             System.out.println("开始连接ZooKeeper...");  
  23.   
  24.             // 创建与ZooKeeper服务器的连接zk  
  25.             String address = "192.168.1.226:2181";  
  26.             int sessionTimeout = 3000;  
  27.             zk = new ZooKeeper(address, sessionTimeout, new Watcher() {  
  28.                 // 监控所有被触发的事件  
  29.                 public void process(WatchedEvent event) {  
  30.                     if (event.getType() == null || "".equals(event.getType())) {  
  31.                         return;  
  32.                     }  
  33.                     System.out.println("已经触发了" + event.getType() + "事件!");  
  34.                 }  
  35.             });  
  36.   
  37.             System.out.println("ZooKeeper连接创建成功!");  
  38.   
  39.             Thread.currentThread().sleep(1000l);  
  40.   
  41.             System.out.println("...");  
  42.             System.out.println("...");  
  43.             System.out.println("...");  
  44.             System.out.println("...");  
  45.   
  46.             // 创建根目录节点  
  47.             // 路径为/tmp_root_path  
  48.             // 节点内容为字符串"我是根目录/tmp_root_path"  
  49.             // 创建模式为CreateMode.PERSISTENT  
  50.             System.out.println("开始创建根目录节点/tmp_root_path...");  
  51.             zk.create("/tmp_root_path""我是根目录/tmp_root_path".getBytes(),  
  52.                     Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
  53.             System.out.println("根目录节点/tmp_root_path创建成功!");  
  54.   
  55.             Thread.currentThread().sleep(1000l);  
  56.   
  57.             System.out.println("...");  
  58.             System.out.println("...");  
  59.             System.out.println("...");  
  60.             System.out.println("...");  
  61.   
  62.             // 创建第一个子目录节点  
  63.             // 路径为/tmp_root_path/childPath1  
  64.             // 节点内容为字符串"我是第一个子目录/tmp_root_path/childPath1"  
  65.             // 创建模式为CreateMode.PERSISTENT  
  66.             System.out.println("开始创建第一个子目录节点/tmp_root_path/childPath1...");  
  67.             zk.create("/tmp_root_path/childPath1",  
  68.                     "我是第一个子目录/tmp_root_path/childPath1".getBytes(),  
  69.                     Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
  70.             System.out.println("第一个子目录节点/tmp_root_path/childPath1创建成功!");  
  71.   
  72.             Thread.currentThread().sleep(1000l);  
  73.   
  74.             System.out.println("...");  
  75.             System.out.println("...");  
  76.             System.out.println("...");  
  77.             System.out.println("...");  
  78.   
  79.             Thread.currentThread().sleep(1000l);  
  80.   
  81.             System.out.println("...");  
  82.             System.out.println("...");  
  83.             System.out.println("...");  
  84.             System.out.println("...");  
  85.   
  86.             // 创建第二个子目录节点  
  87.             // 路径为/tmp_root_path/childPath2  
  88.             // 节点内容为字符串"我是第二个子目录/tmp_root_path/childPath2"  
  89.             // 创建模式为CreateMode.PERSISTENT  
  90.             System.out.println("开始创建第二个子目录节点/tmp_root_path/childPath2...");  
  91.             zk.create("/tmp_root_path/childPath2",  
  92.                     "我是第二个子目录/tmp_root_path/childPath2".getBytes(),  
  93.                     Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);  
  94.             System.out.println("第二个子目录节点/tmp_root_path/childPath2创建成功!");  
  95.   
  96.             Thread.currentThread().sleep(1000l);  
  97.   
  98.             System.out.println("...");  
  99.             System.out.println("...");  
  100.             System.out.println("...");  
  101.             System.out.println("...");  
  102.   
  103.             // 获取第二个子目录节点/tmp_root_path/childPath2节点数据  
  104.             System.out.println("开始获取第二个子目录节点/tmp_root_path/childPath2节点数据...");  
  105.             System.out.println(new String(zk.getData(  
  106.                     "/tmp_root_path/childPath2"truenull)));  
  107.             System.out.println("第二个子目录节点/tmp_root_path/childPath2节点数据获取成功!");  
  108.   
  109.             Thread.currentThread().sleep(1000l);  
  110.   
  111.             System.out.println("...");  
  112.             System.out.println("...");  
  113.             System.out.println("...");  
  114.             System.out.println("...");  
  115.   
  116.             // 修改第一个子目录节点/tmp_root_path/childPath1数据  
  117.             System.out.println("开始修改第一个子目录节点/tmp_root_path/childPath1数据...");  
  118.             zk.setData("/tmp_root_path/childPath1",  
  119.                     "我是修改数据后的第一个子目录/tmp_root_path/childPath1".getBytes(), -1);  
  120.             System.out.println("修改第一个子目录节点/tmp_root_path/childPath1数据成功!");  
  121.   
  122.             Thread.currentThread().sleep(1000l);  
  123.   
  124.             System.out.println("...");  
  125.             System.out.println("...");  
  126.             System.out.println("...");  
  127.             System.out.println("...");  
  128.   
  129.             // 修改第二个子目录节点/tmp_root_path/childPath2数据  
  130.             System.out.println("开始修改第二个子目录节点/tmp_root_path/childPath2数据...");  
  131.             zk.setData("/tmp_root_path/childPath2",  
  132.                     "我是修改数据后的第二个子目录/tmp_root_path/childPath2".getBytes(), -1);  
  133.             System.out.println("修改第二个子目录节点/tmp_root_path/childPath2数据成功!");  
  134.   
  135.             Thread.currentThread().sleep(1000l);  
  136.   
  137.             System.out.println("...");  
  138.             System.out.println("...");  
  139.             System.out.println("...");  
  140.             System.out.println("...");  
  141.   
  142.             // 删除第一个子目录节点  
  143.             System.out.println("开始删除第一个子目录节点/tmp_root_path/childPath1...");  
  144.             zk.delete("/tmp_root_path/childPath1", -1);  
  145.             System.out.println("第一个子目录节点/tmp_root_path/childPath1删除成功!");  
  146.   
  147.             Thread.currentThread().sleep(1000l);  
  148.   
  149.             System.out.println("...");  
  150.             System.out.println("...");  
  151.             System.out.println("...");  
  152.             System.out.println("...");  
  153.   
  154.             // 删除第二个子目录节点  
  155.             System.out.println("开始删除第二个子目录节点/tmp_root_path/childPath2...");  
  156.             zk.delete("/tmp_root_path/childPath2", -1);  
  157.             System.out.println("第二个子目录节点/tmp_root_path/childPath2删除成功!");  
  158.   
  159.             Thread.currentThread().sleep(1000l);  
  160.   
  161.             System.out.println("...");  
  162.             System.out.println("...");  
  163.             System.out.println("...");  
  164.             System.out.println("...");  
  165.   
  166.             // 删除根目录节点  
  167.             System.out.println("开始删除根目录节点/tmp_root_path...");  
  168.             zk.delete("/tmp_root_path", -1);  
  169.             System.out.println("根目录节点/tmp_root_path删除成功!");  
  170.   
  171.             Thread.currentThread().sleep(1000l);  
  172.   
  173.             System.out.println("...");  
  174.             System.out.println("...");  
  175.             System.out.println("...");  
  176.             System.out.println("...");  
  177.   
  178.         } catch (IOException | KeeperException | InterruptedException e) {  
  179.             // TODO Auto-generated catch block  
  180.             e.printStackTrace();  
  181.         } finally {  
  182.             // 关闭连接  
  183.             if (zk != null) {  
  184.                 try {  
  185.                     zk.close();  
  186.                     System.out.println("释放ZooKeeper连接成功!");  
  187.   
  188.                 } catch (InterruptedException e) {  
  189.                     // TODO Auto-generated catch block  
  190.                     e.printStackTrace();  
  191.                 }  
  192.             }  
  193.         }  
  194.   
  195.     }  
  196. }  
        通过以上示例可以看出,我们创建了一个根节点/tmp_root_path,并且在这个根节点下面创建了两个平级的子节点/tmp_root_path/childPath1和/tmp_root_path/childPath2,而我们中间加了一段代码,获取第二个子目录节点/tmp_root_path/childPath2节点数据调用zk的getData()方法时,第二个参数设置为true,即为监控第二个子节点/tmp_root_path/childPath2,执行结果如下:
  1. ...  
  2. ...  
  3. ...  
  4. ...  
  5. 开始连接ZooKeeper...  
  6. ZooKeeper连接创建成功!  
  7. 已经触发了None事件!  
  8. ...  
  9. ...  
  10. ...  
  11. ...  
  12. 开始创建根目录节点/tmp_root_path...  
  13. 根目录节点/tmp_root_path创建成功!  
  14. ...  
  15. ...  
  16. ...  
  17. ...  
  18. 开始创建第一个子目录节点/tmp_root_path/childPath1...  
  19. 第一个子目录节点/tmp_root_path/childPath1创建成功!  
  20. ...  
  21. ...  
  22. ...  
  23. ...  
  24. ...  
  25. ...  
  26. ...  
  27. ...  
  28. 开始创建第二个子目录节点/tmp_root_path/childPath2...  
  29. 第二个子目录节点/tmp_root_path/childPath2创建成功!  
  30. ...  
  31. ...  
  32. ...  
  33. ...  
  34. 开始获取第二个子目录节点/tmp_root_path/childPath2节点数据...  
  35. 我是第二个子目录/tmp_root_path/childPath2  
  36. 第二个子目录节点/tmp_root_path/childPath2节点数据获取成功!  
  37. ...  
  38. ...  
  39. ...  
  40. ...  
  41. 开始修改第一个子目录节点/tmp_root_path/childPath1数据...  
  42. 修改第一个子目录节点/tmp_root_path/childPath1数据成功!  
  43. ...  
  44. ...  
  45. ...  
  46. ...  
  47. 开始修改第二个子目录节点/tmp_root_path/childPath2数据...  
  48. 已经触发了NodeDataChanged事件!  
  49. 修改第二个子目录节点/tmp_root_path/childPath2数据成功!  
  50. ...  
  51. ...  
  52. ...  
  53. ...  
  54. 开始删除第一个子目录节点/tmp_root_path/childPath1...  
  55. 第一个子目录节点/tmp_root_path/childPath1删除成功!  
  56. ...  
  57. ...  
  58. ...  
  59. ...  
  60. 开始删除第二个子目录节点/tmp_root_path/childPath2...  
  61. 第二个子目录节点/tmp_root_path/childPath2删除成功!  
  62. ...  
  63. ...  
  64. ...  
  65. ...  
  66. 开始删除根目录节点/tmp_root_path...  
  67. 根目录节点/tmp_root_path删除成功!  
  68. ...  
  69. ...  
  70. ...  
  71. ...  
  72. 释放ZooKeeper连接成功!  
        可以发现,修改第二个子节点/tmp_root_path/childPath2数据时,触发了NodeDataChanged事件,而对应修改第一个子目录节点/tmp_root_path/childPath1数据,并没有触发该事件,并且,删除第二个子节点/tmp_root_path/childPath2时也没有触发!
        而当我们屏蔽到修改第二个子节点/tmp_root_path/childPath2数据相关代码时,屏蔽掉的部分和执行结果如下:
  1. //          // 修改第二个子目录节点/tmp_root_path/childPath2数据  
  2. //          System.out.println("开始修改第二个子目录节点/tmp_root_path/childPath2数据...");  
  3. //          zk.setData("/tmp_root_path/childPath2",  
  4. //                  "我是修改数据后的第二个子目录/tmp_root_path/childPath2".getBytes(), -1);  
  5. //          System.out.println("修改第二个子目录节点/tmp_root_path/childPath2数据成功!");  
  6. //  
  7. //          Thread.currentThread().sleep(1000l);  
  8. //  
  9. //          System.out.println("...");  
  10. //          System.out.println("...");  
  11. //          System.out.println("...");  
  12. //          System.out.println("...");  
  1. ...  
  2. ...  
  3. ...  
  4. ...  
  5. 开始连接ZooKeeper...  
  6. ZooKeeper连接创建成功!  
  7. 已经触发了None事件!  
  8. ...  
  9. ...  
  10. ...  
  11. ...  
  12. 开始创建根目录节点/tmp_root_path...  
  13. 根目录节点/tmp_root_path创建成功!  
  14. ...  
  15. ...  
  16. ...  
  17. ...  
  18. 开始创建第一个子目录节点/tmp_root_path/childPath1...  
  19. 第一个子目录节点/tmp_root_path/childPath1创建成功!  
  20. ...  
  21. ...  
  22. ...  
  23. ...  
  24. ...  
  25. ...  
  26. ...  
  27. ...  
  28. 开始创建第二个子目录节点/tmp_root_path/childPath2...  
  29. 第二个子目录节点/tmp_root_path/childPath2创建成功!  
  30. ...  
  31. ...  
  32. ...  
  33. ...  
  34. 开始获取第二个子目录节点/tmp_root_path/childPath2节点数据...  
  35. 我是第二个子目录/tmp_root_path/childPath2  
  36. 第二个子目录节点/tmp_root_path/childPath2节点数据获取成功!  
  37. ...  
  38. ...  
  39. ...  
  40. ...  
  41. 开始修改第一个子目录节点/tmp_root_path/childPath1数据...  
  42. 修改第一个子目录节点/tmp_root_path/childPath1数据成功!  
  43. ...  
  44. ...  
  45. ...  
  46. ...  
  47. 开始删除第一个子目录节点/tmp_root_path/childPath1...  
  48. 第一个子目录节点/tmp_root_path/childPath1删除成功!  
  49. ...  
  50. ...  
  51. ...  
  52. ...  
  53. 开始删除第二个子目录节点/tmp_root_path/childPath2...  
  54. 已经触发了NodeDeleted事件!  
  55. 第二个子目录节点/tmp_root_path/childPath2删除成功!  
  56. ...  
  57. ...  
  58. ...  
  59. ...  
  60. 开始删除根目录节点/tmp_root_path...  
  61. 根目录节点/tmp_root_path删除成功!  
  62. ...  
  63. ...  
  64. ...  
  65. ...  
  66. 释放ZooKeeper连接成功!  
        执行结果显而易见,删除第二个子节点/tmp_root_path/childPath2时触发了NodeDataChanged事件,但是修改第一个子节点和删除第一个子节点并没有触发!

        我们再做一个变更,修改第二个子节点/tmp_root_path/childPath2两次,那么执行结果如何呢?添加的代码及执行结果如下:

  1. // 第二次修改第二个子目录节点/tmp_root_path/childPath2数据  
  2. System.out.println("开始第二次修改第二个子目录节点/tmp_root_path/childPath2数据...");  
  3. zk.setData("/tmp_root_path/childPath2",  
  4.         "我是第二次修改数据后的第二个子目录/tmp_root_path/childPath2".getBytes(), -1);  
  5. System.out.println("第二次修改第二个子目录节点/tmp_root_path/childPath2数据成功!");  
  6.   
  7. Thread.currentThread().sleep(1000l);  
  8.   
  9. System.out.println("...");  
  10. System.out.println("...");  
  11. System.out.println("...");  
  12. System.out.println("...");  
  1. ...  
  2. ...  
  3. ...  
  4. ...  
  5. 开始连接ZooKeeper...  
  6. ZooKeeper连接创建成功!  
  7. 已经触发了None事件!  
  8. ...  
  9. ...  
  10. ...  
  11. ...  
  12. 开始创建根目录节点/tmp_root_path...  
  13. 根目录节点/tmp_root_path创建成功!  
  14. ...  
  15. ...  
  16. ...  
  17. ...  
  18. 开始创建第一个子目录节点/tmp_root_path/childPath1...  
  19. 第一个子目录节点/tmp_root_path/childPath1创建成功!  
  20. ...  
  21. ...  
  22. ...  
  23. ...  
  24. ...  
  25. ...  
  26. ...  
  27. ...  
  28. 开始创建第二个子目录节点/tmp_root_path/childPath2...  
  29. 第二个子目录节点/tmp_root_path/childPath2创建成功!  
  30. ...  
  31. ...  
  32. ...  
  33. ...  
  34. 开始获取第二个子目录节点/tmp_root_path/childPath2节点数据...  
  35. 我是第二个子目录/tmp_root_path/childPath2  
  36. 第二个子目录节点/tmp_root_path/childPath2节点数据获取成功!  
  37. ...  
  38. ...  
  39. ...  
  40. ...  
  41. 开始修改第一个子目录节点/tmp_root_path/childPath1数据...  
  42. 修改第一个子目录节点/tmp_root_path/childPath1数据成功!  
  43. ...  
  44. ...  
  45. ...  
  46. ...  
  47. 开始修改第二个子目录节点/tmp_root_path/childPath2数据...  
  48. 已经触发了NodeDataChanged事件!  
  49. 修改第二个子目录节点/tmp_root_path/childPath2数据成功!  
  50. ...  
  51. ...  
  52. ...  
  53. ...  
  54. 开始第二次修改第二个子目录节点/tmp_root_path/childPath2数据...  
  55. 第二次修改第二个子目录节点/tmp_root_path/childPath2数据成功!  
  56. ...  
  57. ...  
  58. ...  
  59. ...  
  60. 开始删除第一个子目录节点/tmp_root_path/childPath1...  
  61. 第一个子目录节点/tmp_root_path/childPath1删除成功!  
  62. ...  
  63. ...  
  64. ...  
  65. ...  
  66. 开始删除第二个子目录节点/tmp_root_path/childPath2...  
  67. 第二个子目录节点/tmp_root_path/childPath2删除成功!  
  68. ...  
  69. ...  
  70. ...  
  71. ...  
  72. 开始删除根目录节点/tmp_root_path...  
  73. 根目录节点/tmp_root_path删除成功!  
  74. ...  
  75. ...  
  76. ...  
  77. ...  
  78. 释放ZooKeeper连接成功!  
        仅仅是第一次修改第二个子节点/tmp_root_path/childPath2数据时触发了NodeDataChanged事件,第二次修改与删除均未触发!

        而当我们在第二次修改第二个子节点/tmp_root_path/childPath2数据前先获取一遍,并且watch设置为true,那么两次对第二个子节点/tmp_root_path/childPath2数据的修改均会触发NodeDataChanged事件,并且获取根目录节点数据时,也仅是监控根目录,其子目录的变化不会触发NodeDataChanged事件,读者可自行尝试!


        结论:

        getData()方法仅仅监控对应节点的一次数据变化,无论是数据修改还是删除!若要每次对应节点发生变化都被监测到,那么每次都得先调用getData()方法获取一遍数据!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值