Next, I went on to analyze the source code of the Watcher related classes.
ClientWatchManager
public Set<Watcher> materialize(Watcher.Event.KeeperState state, Watcher.Event.EventType type, String path);
This interface has only one method and needs to be implemented. This method represents the Watcher collection to be notified when an event occurs, which may be an empty collection.
ZKWatchManager
1. ZKWatchManager is the internal class of ZooKeeper, which implements ClientWatchManager.
2. ZKWatchManager defines three Map key value pairs. The key is the node path and the value is Watcher. It respectively corresponds to the Watcher of data change, whether the node has a Watcher or not, and the Watcher of child node change.
static class ZKWatchManager implements ClientWatchManager { //watchers of data change private final Map<String, Set<Watcher>> dataWatches = new HashMap<String, Set<Watcher>>(); //watchers whether nodes exist or not private final Map<String, Set<Watcher>> existWatches = new HashMap<String, Set<Watcher>>(); //watchers with children changing private final Map<String, Set<Watcher>> childWatches = new HashMap<String, Set<Watcher>>();
3. Material method
This method returns the Watcher collection to be notified after the event. In this method, the corresponding event type will be determined first according to the EventType type, and then the corresponding operation will be made according to the different event types. For example, for the None type, i.e. there is no event, the Watcher corresponding to the clientPath will be deleted from the three key value pairs, and then the remaining Watcher set will be added to the result set; for the NodeDataChanged and nodechreated events , which removes the Watcher corresponding to the clientPath from dataWatches and existWatches, and then adds the remaining Watcher collection to the result collection.
@Override public Set<Watcher> materialize(Watcher.Event.KeeperState state, Watcher.Event.EventType type, String clientPath) { //Return result set Set<Watcher> result = new HashSet<Watcher>(); switch (type) {//Event type case None://No type //Add default watcher result.add(defaultWatcher); //Determine whether to clear according to whether the status of disableAutoWatchReset and Zookeeper is synchronous connection boolean clear = disableAutoWatchReset && state != Watcher.Event.KeeperState.SyncConnected; //Operate on three different watchermaps synchronized(dataWatches) { for(Set<Watcher> ws: dataWatches.values()) { // Add to result set result.addAll(ws); } if (clear) { // Need to 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:// Node data changes case NodeCreated:// Create node synchronized (dataWatches) { //Remove the Watcher corresponding to the clientPath and add all to the result collection addTo(dataWatches.remove(clientPath), result); } synchronized (existWatches) { //Remove the Watcher corresponding to the clientPath and add all to the result collection addTo(existWatches.remove(clientPath), result); } break; case NodeChildrenChanged: // Node child changes synchronized (childWatches) { // Remove the Watcher corresponding to the clientPath and add all to the result collection addTo(childWatches.remove(clientPath), result); } break; case NodeDeleted:// Delete node synchronized (dataWatches) { // Remove the Watcher corresponding to the clientPath and add all to the result collection addTo(dataWatches.remove(clientPath), result); } // XXX This shouldn't be needed, but just in case synchronized (existWatches) { Set<Watcher> list = existWatches.remove(clientPath); if (list != null) { addTo(list, result); LOG.warn("We are triggering an exists watch for delete! Shouldn't happen!"); } } synchronized (childWatches) { //Remove the Watcher corresponding to the clientPath and add all to the result collection 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; } }