一、前言
前面已經分析了Zookeeper持久話相關的類,下面接著分析Zookeeper中的Watcher機制所涉及到的類。
二、總體框圖
對於Watcher機制而言,主要涉及的類主要如下。
說明:
Watcher,介面型別,其定義了process方法,需子類實現。
Event,介面型別,Watcher的內部類,無任何方法。
KeeperState,列舉型別,Event的內部類,表示Zookeeper所處的狀態。
EventType,列舉型別,Event的內部類,表示Zookeeper中發生的事件型別。
WatchedEvent,表示對ZooKeeper上發生變化後的反饋,包含了KeeperState和EventType。
ClientWatchManager,介面型別,表示客戶端的Watcher管理者,其定義了materialized方法,需子類實現。
ZKWatchManager,Zookeeper的內部類,繼承ClientWatchManager。
MyWatcher,ZooKeeperMain的內部類,繼承Watcher。
ServerCnxn,介面型別,繼承Watcher,表示客戶端與服務端的一個連線。
WatchManager,管理Watcher。
三、Watcher原始碼分析
3.1 內部類
Event,介面型別,表示事件代表的狀態,除去其內部類,其原始碼結構如下
public interface Event {}
說明:可以看到,Event介面並沒有定義任何屬性和方法,但是其包含了KeeperState和EventType兩個內部列舉類。
3.2 介面方法
abstract public void process(WatchedEvent event);
說明:其代表了實現Watcher介面時必須實現的的方法,即定義進行處理,WatchedEvent表示觀察的事件。
四、Event原始碼分析
3.1 內部類
1. KeeperState
public enum KeeperState { // 事件發生時Zookeeper的狀態 /** Unused, this state is never generated by the server */ @Deprecated // 未知狀態,不再使用,伺服器不會產生此狀態 Unknown (-1), /** The client is in the disconnected state - it is not connected * to any server in the ensemble. */ // 斷開 Disconnected (0), /** Unused, this state is never generated by the server */ @Deprecated // 未同步連線,不再使用,伺服器不會產生此狀態 NoSyncConnected (1), /** The client is in the connected state - it is connected * to a server in the ensemble (one of the servers specified * in the host connection parameter during ZooKeeper client * creation). */ // 同步連線狀態 SyncConnected (3), /** * Auth failed state */ // 認證失敗狀態 AuthFailed (4), /** * The client is connected to a read-only server, that is the * server which is not currently connected to the majority. * The only operations allowed after receiving this state is * read operations. * This state is generated for read-only clients only since * read/write clients aren't allowed to connect to r/o servers. */ // 只讀連線狀態 ConnectedReadOnly (5), /** * SaslAuthenticated: used to notify clients that they are SASL-authenticated, * so that they can perform Zookeeper actions with their SASL-authorized permissions. */ // SASL認證通過狀態 SaslAuthenticated(6), /** The serving cluster has expired this session. The ZooKeeper * client connection (the session) is no longer valid. You must * create a new client connection (instantiate a new ZooKeeper * instance) if you with to access the ensemble. */ // 過期狀態 Expired (-112); // 代表狀態的整形值 private final int intValue; // Integer representation of value // for sending over wire // 建構函式 KeeperState(int intValue) { this.intValue = intValue; } // 返回整形值 public int getIntValue() { return intValue; } // 從整形值構造相應的狀態 public static KeeperState fromInt(int intValue) { switch(intValue) { case -1: return KeeperState.Unknown; case 0: return KeeperState.Disconnected; case 1: return KeeperState.NoSyncConnected; case 3: return KeeperState.SyncConnected; case 4: return KeeperState.AuthFailed; case 5: return KeeperState.ConnectedReadOnly; case 6: return KeeperState.SaslAuthenticated; case -112: return KeeperState.Expired; default: throw new RuntimeException("Invalid integer value for conversion to KeeperState"); } } }
說明:KeeperState是一個列舉類,其定義了在事件發生時Zookeeper所處的各種狀態,其還定義了一個從整形值返回對應狀態的方法fromInt。
2. EventType
public enum EventType { // 事件型別 // 無 None (-1), // 結點建立 NodeCreated (1), // 結點刪除 NodeDeleted (2), // 結點資料變化 NodeDataChanged (3), // 結點子節點變化 NodeChildrenChanged (4); // 代表事件型別的整形 private final int intValue; // Integer representation of value // for sending over wire // 建構函式 EventType(int intValue) { this.intValue = intValue; } // 返回整形 public int getIntValue() { return intValue; } // 從整形構造相應的事件 public static EventType fromInt(int intValue) { switch(intValue) { case -1: return EventType.None; case 1: return EventType.NodeCreated; case 2: return EventType.NodeDeleted; case 3: return EventType.NodeDataChanged; case 4: return EventType.NodeChildrenChanged; default: throw new RuntimeException("Invalid integer value for conversion to EventType"); } } } }
說明:EventType是一個列舉類,其定義了事件的型別(如建立節點、刪除節點等事件),同時,其還定義了一個從整形值返回對應事件型別的方法fromInt。
五、WatchedEvent
5.1 類的屬性
public class WatchedEvent { // Zookeeper的狀態 final private KeeperState keeperState; // 事件型別 final private EventType eventType; // 事件所涉及節點的路徑 private String path; }
說明:WatchedEvent類包含了三個屬性,分別代表事件發生時Zookeeper的狀態、事件型別和發生事件所涉及的節點路徑。
5.2 建構函式
1. public WatchedEvent(EventType eventType, KeeperState keeperState, String path)型建構函式
public WatchedEvent(EventType eventType, KeeperState keeperState, String path) { // 初始化屬性 this.keeperState = keeperState; this.eventType = eventType; this.path = path; }
說明:建構函式傳入了三個引數,然後分別對屬性進行賦值操作。
2. public WatchedEvent(WatcherEvent eventMessage)型建構函式
public WatchedEvent(WatcherEvent eventMessage) { // 從eventMessage中取出相應屬性進行賦值 keeperState = KeeperState.fromInt(eventMessage.getState()); eventType = EventType.fromInt(eventMessage.getType()); path = eventMessage.getPath(); }
說明:建構函式傳入了WatcherEvent引數,之後直接從該引數中取出相應屬性進行賦值操作。
對於WatchedEvent類的方法而言,相對簡單,包含了幾個getXXX方法,用於獲取相應的屬性值。
六、ClientWatchManager
6.1 介面方法
public Set<Watcher> materialize(Watcher.Event.KeeperState state, Watcher.Event.EventType type, String path);
說明:該方法表示事件發生時,返回需要被通知的Watcher集合,可能為空集合。
七、ZKWatchManager
7.1 類的屬性
private static class ZKWatchManager implements ClientWatchManager { // 資料變化的Watchers private final Map<String, Set<Watcher>> dataWatches = new HashMap<String, Set<Watcher>>(); // 節點存在與否的Watchers private final Map<String, Set<Watcher>> existWatches = new HashMap<String, Set<Watcher>>(); // 子節點變化的Watchers private final Map<String, Set<Watcher>> childWatches = new HashMap<String, Set<Watcher>>(); }
說明:ZKWatchManager實現了ClientWatchManager,並定義了三個Map鍵值對,鍵為節點路徑,值為Watcher。分別對應資料變化的Watcher、節點是否存在的Watcher、子節點變化的Watcher。
7.2 核心方法分析
1. materialize方法
public Set<Watcher> materialize(Watcher.Event.KeeperState state, Watcher.Event.EventType type, String clientPath) { // 新生成結果Watcher集合 Set<Watcher> result = new HashSet<Watcher>(); switch (type) { // 確定事件型別 case None: // 無型別 // 新增預設Watcher result.add(defaultWatcher); // 是否需要清空(提取對zookeeper.disableAutoWatchReset欄位進行配置的值、Zookeeper的狀態是否為同步連線) boolean clear = ClientCnxn.getDisableAutoResetWatch() && state != Watcher.Event.KeeperState.SyncConnected; synchronized(dataWatches) { // 同步塊 for(Set<Watcher> ws: dataWatches.values()) { // 新增至結果集合 result.addAll(ws); } if (clear) { // 是否需要清空 dataWatches.clear(); } } synchronized(existWatches) { // 同步塊 for(Set<Watcher> ws: existWatches.values()) { // 新增至結果集合 result.addAll(ws); } if (clear) { // 是否需要清空 existWatches.clear(); } } synchronized(childWatches) { // 同步塊 for(Set<Watcher> ws: childWatches.values()) { // 新增至結果集合 result.addAll(ws); } if (clear) { // 是否需要清空 childWatches.clear(); } } // 返回結果 return result; case NodeDataChanged: // 節點資料變化 case NodeCreated: // 建立節點 synchronized (dataWatches) { // 同步塊 // 移除clientPath對應的Watcher後全部新增至結果集合 addTo(dataWatches.remove(clientPath), result); } synchronized (existWatches) { // 移除clientPath對應的Watcher後全部新增至結果集合 addTo(existWatches.remove(clientPath), result); } break; case NodeChildrenChanged: // 節點子節點變化 synchronized (childWatches) { // 移除clientPath對應的Watcher後全部新增至結果集合 addTo(childWatches.remove(clientPath), result); } break; case NodeDeleted: // 刪除節點 synchronized (dataWatches) { // 移除clientPath對應的Watcher後全部新增至結果集合 addTo(dataWatches.remove(clientPath), result); } // XXX This shouldn't be needed, but just in case synchronized (existWatches) { // 移除clientPath對應的Watcher Set<Watcher> list = existWatches.remove(clientPath); if (list != null) { // 移除clientPath對應的Watcher後全部新增至結果集合 addTo(existWatches.remove(clientPath), result); LOG.warn("We are triggering an exists watch for delete! Shouldn't happen!"); } } synchronized (childWatches) { // 移除clientPath對應的Watcher後全部新增至結果集合 addTo(childWatches.remove(clientPath), result); } break; default: // 預設處理 String msg = "Unhandled watch event type " + type + " with state " + state + " on path " + clientPath; LOG.error(msg); throw new RuntimeException(msg); } // 返回結果集合 return result; } }
說明:該方法在事件發生後,返回需要被通知的Watcher集合。在該方法中,首先會根據EventType型別確定相應的事件型別,然後根據事件型別的不同做出相應的操作,如針對None型別,即無任何事件,則首先會從三個鍵值對中刪除clientPath對應的Watcher,然後將剩餘的Watcher集合新增至結果集合;針對NodeDataChanged和NodeCreated事件而言,其會從dataWatches和existWatches中刪除clientPath對應的Watcher,然後將剩餘的Watcher集合新增至結果集合。
八、總結
針對Watcher機制的第一部分的原始碼分析就已經完成,可以看到此部分的原始碼相對簡單,之後會分析org.apache.zookeeper.server下的WatchManager和ClientWatchManager所在外部類ZooKeeper,也謝謝各位園友的觀看~