转载链接:https://blog.csdn.net/liyiming2017/article/details/83276706

需求理解
我们先回顾一下例子的需求,此客户端有如下四个需求:

1、它接收如下参数:

ZooKeeper服务的地址
被监控的znode的名称
可执行命令参数
2、它会取得znode上关联的数据,然后执行命令

3、如果znode变化,客户端重新拉取数据,再次执行命令

4、如果znode消失了,客户端杀掉进行的执行命令

如果你已经学习过或者了解过该例子文档的内容,你应该知道该程序做的事情就是接受用户输入的系统命令,然后监控zookeeper的znode,一旦znode存在,或者发生了变化,程序会把znode最新的数据存入文件,然后起一个线程执行用户的命令,同时还会起两个线程输出执行结果及日志。

举例类比
为了帮助理解,这里举个现实的例子--警察抓坏人:

公安成立了一个行动组准备在嫌疑人住所进行抓捕,警方人员安排如下:

  1. 组长A负责总指挥
  2. 警察B负责监控嫌疑人,并与组长A联络
  3. 警察C,D,E,F埋伏在嫌疑人住所前后左右,准备实施抓捕

整个抓捕过程是这样的:

  1. 组长A下达命令安排后,B,C各就各位(对象A做初始化工作)
  2. B开始监控嫌疑人,一旦嫌疑人进入警察布下的埋伏圈,则马上通知组长A(对象B为watcher,嫌疑人为被监听的znode。A注册为B的listener,在B的监听回调中被触发)
  3. 组长A得到通知后,马上命令C、D、E、F执行抓捕。(C,D,E是被A调用干活的线程)

理解了上线的例子,我们继续对程序进行讲解。

Executor和DataMonitor
本例中有两个主要类,职能如下:

Executor,它是程序的入口。负责初始化zookeeper、DataMonitor,把自己注册为DataMonitor的监听者,一旦DataMonitor监听到变化后,会通知它执行业务操作。

他是例子中的组长A,它有几个内部类是前面说的警员C、D、E、F,负责干活。

DataMonitor,他负责监控znode,发现znode变化后,通知listener执行业务逻辑,同时再次监控znode:

他是例子中的警察B,负责监控犯人,并通知A。

通过以上讲解,这两个主要类所负责的工作应该已经可以充分的理解了。接下来我们针对这两个类进入更为详细的讲解。

内部类和接口:
Executor:

StreamWriter。继承Thread,以多线程的形式负责把执行的结果输出。相当于例子中的警察C、D、E、F

DataMonitor:

DataMonitorListener。DataMonitor一旦监控到znode的变化,立即调用自己持有的listener(实现此接口的对象)的exists方法(通知它的监听者)。

继承关系:
Executor:

  • 实现watcher:

    • 监听zookeeper连接的变化,实现process()方法,把事件传递给DataMonitor处理。
  • 实现DataMonitor中定义的接口DataListener:
    • 实现exists()方法,处理znode变化的具体逻辑。
  • 实现runnable类:
    • run()方法中阻塞主线程,让程序转为事件驱动。
public class Executor implements Watcher, Runnable, DataMonitor.DataMonitorListener{}

DataMonitor:

  • 实现watcher:

    • 监听znode变化。实现process()方法,通过zk.exist()方法再次监听,再次设置自己为zookeeper.exist()的回调(实现不断监听,事件驱动)。同时数据返回后,立即进入下面的回调函数处理
  • 实现StatCallback:
    • 这是zookeeper.exist()操作回调对象。实现processResult()方法,调用DataMonitor持有的listener(也就是Excutor)的exists()方法执行逻辑。
public class DataMonitor implements Watcher, StatCallback{} 

引用关系:
Executor:

  • DataMonitor dm;
  • ZooKeeper zk; //ZooKeeper的连接
  • Process child; //真正执行系统命令的子线程,相当于警察C,D,E,F之一。

DataMonitor:

  • ZooKeeper zk; //和Executor是同一个引用。Executor通过构造函数传入
  • DataMonitorListener listener; //executor对象,Executor通过构造函数传入自己

图解

Executor和DataMonitor的关系如下:

两者通过Executor作为主入口,初始化DataMonitor和ZooKeeper对象后,阻塞主线程。转为事件驱动。即通过DataMonitor监控znode上的事件来驱动程序逻辑。

整个流程如下:

  1. Excutor把自己注册为DataMonitor的监听
  2. DataMonitor实现watcher接口,并监听znode
  3. znode变化时,触发DataMonitor的监听回调
  4. 回调中通过ZooKeeper.exist() 再次监听znode
  5. 上一步exist的回调方法中,调用监听自己的Executor,执行业务逻辑6
  6. Executor启新的线程执行命令
  7. Executor启新的线程打印执行命令的输

ZooKeeper java例子解读的更多相关文章

  1. ZooKeeper Java例子(六)

    A Simple Watch Client 为了向你介绍ZooKeeper Java API,我们开发了一个非常简单的监视器客户端.ZooKeeper客户端监视一个ZooKeeper节点的改变并且通过 ...

  2. Java问题解读系列之String相关---String类为什么是final的?

    今天看到一篇名为<Java开发岗位面试题归类汇总>的博客,戳进去看了一下题目,觉得有必要夯实一下基本功了,所以打算边学边以博客的形式归纳总结,每天一道题, 并将该计划称为java问题解读系 ...

  3. 9. 使用ZooKeeper Java API编程

    ZooKeeper是用Java开发的,3.4.6版本的Java API文档可以在http://zookeeper.apache.org/doc/r3.4.6/api/index.html上找到. Ti ...

  4. Zookeeper java api

     Zookeeper java api 主要有以下几个: 方法名称 描述 String create(final String path, byte data[], List acl, CreateM ...

  5. 14.ZooKeeper Java API 使用样例

    转自:http://www.aboutyun.com/thread-7332-1-1.html package com.taobao.taokeeper.research.sample; import ...

  6. ZooKeeper Java Example

    A Simple Watch Client Requirements Program Design The Executor Class The DataMonitor Class Complete ...

  7. Docker Java 例子

    版权所有,未经许可,禁止转载 章节 Docker 介绍 Docker 和虚拟机的区别 Docker 安装 Docker Hub Docker 镜像(image) Docker 容器(container ...

  8. zookeeper java调用及权限控制

    import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.util.ArrayLis ...

  9. zookeeper - java操作

    ZKUtils.java package test; import java.io.IOException; import java.util.concurrent.CountDownLatch; i ...

随机推荐

  1. delegate作为操作符的使用

    lambda表达式的出现基本上取代了delegate操作符的使用 public MainWindow() { InitializeComponent(); this.button1.Click += ...

  2. 使用xpath爬取猫眼电影排行榜

    最近在学习xpath,在网上找资料的时候,发现一个新手经常拿来练手的项目,爬取猫眼电影前一百名排行的信息,很多都是跟崔庆才的很雷同,基本照抄.这里就用xpath自己写了一个程序,同样也是爬取猫眼电影, ...

  3. java实现spark常用算子之distinct

    import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.a ...

  4. 将数据导出到 excel ,然后下载下来

    private static final String SHEET_NAME = "培养计划表"; /** * @param response * @param trainingN ...

  5. jq sku实现

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. 配置Linux静态IP地址

  7. 模块之time与datetime

    模块之time与datetime import time print (time.clock()) print(time.process_time()) #测量处理器运算时间 print(time.a ...

  8. Idea 汉化后定位和系统设置打不开到问题

    百度网盘:此汉化包已经修正过,拿来直接可以用 链接:https://pan.baidu.com/s/1wm3NbYSM9Gtsdu2EHQPMIA 密码:qdr3 1.系统设置(setting)外观选 ...

  9. ArcMap常用操作

    1.矢量数据融合 数据管理->制图综合->融合 Data Management Tools -> Generalization -> Dissolve

  10. RocketMQ和Kafka的差异对比

    Broker差异 主从差异: kafka的master/slave是基于partition维度的,而rocketmq是基于broker维度的:kafka的master/slave是可以切换的,而roc ...