1. 程式人生 > >ZooKeeper官方Java例子解讀

ZooKeeper官方Java例子解讀

ZooKeeper官方提供了一個Java監聽的例子,本文是我對該例子的學習筆記。可以做為幫助理解此例子的資料:

需求理解

我們先回顧一下例子的需求,此客戶端有如下四個需求:

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啟新的執行緒列印執行命令的輸出