zookeeper 的 watcher 机制,可以分为四个过程:
客户端注册 watcher。
服务端处理 watcher。
服务端触发 watcher 事件。
客户端回调 watcher。
其中客户端注册 watcher 有三种方式,调用客户端 API 可以分别通过 getData、exists、getChildren 实现,利用前面章节创建的 maven 工程,新建 WatcherDemo 类,以 exists 方法举例说明其原理。
实例 public class WatcherDemo implements Watcher { static ZooKeeper zooKeeper; static { try { zooKeeper = new ZooKeeper("192.168.3.39:2181", 4000,new WatcherDemo()); } catch (IOException e) { e.printStackTrace(); } } @Override public void process(WatchedEvent event) { System.out.println("eventType:"+event.getType()); if(event.getType()==Event.EventType.NodeDataChanged){ try { zooKeeper.exists(event.getPath(),true); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException, KeeperException, InterruptedException { String path="/watcher"; if(zooKeeper.exists(path,false)==null) { zooKeeper.create("/watcher", "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } Thread.sleep(1000); System.out.println("-----------"); //true表示使用zookeeper实例中配置的watcher Stat stat=zooKeeper.exists(path,true); System.in.read(); } }
1、客户端发送事件通知请求 在 Zookeeper 类调用 exists 方法时候,把创建事件监听封装到 request 对象中,watch 属性设置为 true,待服务端返回 response 后把监听事件封装到客户端的 ZKWatchManager 类中。
2、服务端处理 watcher 事件的请求
服务端 NIOServerCnxn 类用来处理客户端发送过来的请求,最终调用到 FinalRequestProcessor,其中有一段源码添加客户端发送过来的 watcher 事件:
然后进入 statNode 方法,在 DataTree 类方法中添加 watcher 事件,并保存至 WatchManager 的 watchTable 与 watchTable 中。
3、服务端触发 watcher 事件流程:
若服务端某个被监听的节点发生事务请求,服务端处理请求过程中调用 FinalRequestProcessor 类 processRequest 方法中的代码如下所示:
package com.runoob.zookeeper; import org.apache.zookeeper.*; import java.io.IOException; import java.util.concurrent.CountDownLatch; public class ConnectionDemo { public static void main(String[] args) { try { final CountDownLatch countDownLatch=new CountDownLatch(1); ZooKeeper zooKeeper= new ZooKeeper("192.168.3.35:2181" , 4000, new Watcher() { @Override public void process(WatchedEvent event) { if(Event.KeeperState.SyncConnected==event.getState()){ //如果收到了服务端的响应事件,连接成功 countDownLatch.countDown(); } } }); countDownLatch.await(); System.out.println(zooKeeper.getState()); zooKeeper.create("/runoob","0".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (KeeperException e) { e.printStackTrace(); } } }
package com.runoob.zookeeper; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.zookeeper.data.Stat; public class CuratorDemo { public static void main(String[] args) throws Exception { CuratorFramework curatorFramework=CuratorFrameworkFactory. builder().connectString("192.168.3.33:2181," + "192.168.3.35:2181,192.168.3.37:2181"). sessionTimeoutMs(4000).retryPolicy(new ExponentialBackoffRetry(1000,3)). namespace("").build(); curatorFramework.start(); Stat stat=new Stat(); byte[] bytes = curatorFramework.getData().storingStatIn(stat).forPath("/runoob"); System.out.println(new String(bytes)); curatorFramework.close(); } }
package com.runoob.zookeeper; import org.apache.zookeeper.*; import org.apache.zookeeper.data.Stat; import java.io.IOException; public class WatcherDemo implements Watcher { static ZooKeeper zooKeeper; static { try { zooKeeper = new ZooKeeper("192.168.3.39:2181", 4000,new WatcherDemo()); } catch (IOException e) { e.printStackTrace(); } } @Override public void process(WatchedEvent event) { System.out.println("eventType:"+event.getType()); if(event.getType()==Event.EventType.NodeDataChanged){ try { zooKeeper.exists(event.getPath(),true); } catch (KeeperException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException, KeeperException, InterruptedException { String path="/watcher"; if(zooKeeper.exists(path,false)==null) { zooKeeper.create("/watcher", "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } Thread.sleep(1000); System.out.println("-----------"); //true表示使用zookeeper实例中配置的watcher Stat stat=zooKeeper.exists(path,true); System.in.read(); } }
package com.runoob.zookeeper; import static org.junit.Assert.assertTrue; import org.junit.Test; /** * Unit test for simple ConnnectedDemo. */ public class ConnnectedDemoTest { /** * Rigorous Test :-) */ @Test public void shouldAnswerWithTrue() { assertTrue( true ); } }