數(shù)據(jù)變更的通知祝迂。是zookeeper發(fā)布/訂閱的基礎。
概念
- client向zkServer發(fā)送請求缺狠,說问慎,我想要監(jiān)聽某個節(jié)點的修改。
- zkServer說挤茄,好的如叼。
- zk的節(jié)點一旦有變化,zkServer會通知所有訂閱這個節(jié)點的client穷劈,說笼恰,xxx這個節(jié)點有變化。
- client收到server的通知后歇终,反查server端這個節(jié)點的信息社证,拿到具體的變化信息。反查函數(shù)其實是watcher的回調函數(shù)评凝,在定義的時候追葡,就定義好了要怎么反查。
以此來做到奕短,針對某一個節(jié)點的監(jiān)聽宜肉。
watcher事件
上面說了,監(jiān)聽某個節(jié)點的變化翎碑,那都有什么變化呢
只需要關注type不為空的那幾個
- 節(jié)點創(chuàng)建
- 節(jié)點刪除
- 節(jié)點數(shù)據(jù)更新
- 子節(jié)點列表更新(是子節(jié)點創(chuàng)建或者刪除谬返,子節(jié)點內容變更,不是列表更新)
client注冊watcher的過程
注冊的入口
- 在創(chuàng)建client的時候日杈,zkClient中有帶watcher的構造函數(shù)遣铝。
public Zookeeper(String connectStr, int sessionTimeout, Watcher watcher);
當注冊了默認的watcher的時候,client在getData設置watcher的時候达椰,直接用true翰蠢,就用到了默認的wather。
- getData啰劲、getChildren梁沧、exist
public byte[] getData(String path, boolean watch, Stat stat); // 就是這里,true蝇裤,就用默認的wather來注冊watcher
public byte[] getData(final String path, Watcher watcher, Stat stat);
別看名字是getData,這幾個方法就是注冊watcher的方法廷支。
注冊的過程
client在調用getData之后,客戶端會將watcher信息栓辜,封裝到request中恋拍,將requst發(fā)送給server。
client等待server的返回藕甩,收到server說注冊成功的返回后施敢,client會將watcher信息保存到watcherManager中。
watcherManager是兩個map。
/**
* key為節(jié)點的路徑僵娃。value為所有監(jiān)聽該節(jié)點的watcher
*/
Map<String, Set<Watcher>> watchTable;
/**
* key為Watcher概作。value為該watcher監(jiān)聽的所有節(jié)點path
*/
Map<Watcher, Set<String>> watch2Paths;
watcher觸發(fā)的過程
一旦節(jié)點變動,觸發(fā)了watcher默怨。
封裝watcherEvent
首先將通知狀態(tài)(KeeperState)讯榕、事件類型(EventType)以及節(jié)點路徑(Path)封裝成一個WatcherEvent對象。查詢watcherManager
去watcherManager找監(jiān)聽這個節(jié)點的client的watcher匙睹。遍歷愚屁,一個一個通知。然后痕檬,重點來了霎槐,拿到watchet之后,用完就刪除谆棺。也就說栽燕,watcher是一次性的,要持續(xù)監(jiān)聽某個節(jié)點就要持續(xù)注冊watcher改淑。調用process方法觸發(fā)watcher
第2步中碍岔,拿到了所有的watcher,調用watcher中的process方法朵夏。process方法很簡單蔼啦,就是回調client,你監(jiān)聽的這個節(jié)點變動了仰猖。-
client收到watcher的process后捏肢。框架層會調用client的process方法饥侵。client自己的process是業(yè)務相關的代碼了鸵赫,得自己實現(xiàn)。比如