1.Curator Cache 与原生ZooKeeper Wacher区别
原生的ZooKeeper Wacher是一次性的:一个Wacher一旦触发就会被移出,如果你想要反复使用Wacher,就要在Wacher被移除后重新注册,使用起来很麻烦。使用Curator Cache 可以反复使用Wacher了。
2.Curator Cache 和Curator Wacher区别
2.相关类
Curator Cache主要提供了一下三组类,分别用于实现对节点的监听,子节点的监听和二者的混合:
1.NodeCache,NodeCacheListener,ChildData,节点创建,节点数据内容变更,不能监听节点删除。
2.PathChildrenCache,PathChildrenCacheListener,PathChildrenCacheEvent监听指定节点的子节点的变更包括添加,删除,子节点数据数据变更这三类。
3.TreeCache,TreeCacheListener,TreeCacheEvent,TreeCacheSelector
3.节点监听
package cn.francis.maven.hello.ZooKeeper; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.cache.NodeCache; import org.apache.curator.framework.recipes.cache.NodeCacheListener; import org.apache.curator.framework.recipes.cache.TreeCache; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.test.TestingServer; import org.apache.curator.utils.CloseableUtils; import org.apache.zookeeper.CreateMode; public class NodeCacheDemo { public static void main(String[]args) throws Exception{ TestingServer server=null; CuratorFramework client=null; NodeCache nodeCache=null; String path="/francis/nodecache/a"; try{ server=new TestingServer(); client= CuratorFrameworkFactory.newClient(server.getConnectString(), new ExponentialBackoffRetry(1000,3)); client.start(); path=client.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL).forPath(path,"init".getBytes()); nodeCache=new NodeCache(client,path,false); nodeCache.start(); addListener(nodeCache); client.setData().forPath(path,"hello".getBytes()); Thread.sleep(1000); client.delete().deletingChildrenIfNeeded().forPath(path); Thread.sleep(Integer.MAX_VALUE); }catch(Exception e){ e.printStackTrace(); }finally{ //这里因为是测试,没有加他们。 //CloseableUtils.closeQuietly(nodeCache); /// CloseableUtils.closeQuietly(client); // CloseableUtils.closeQuietly(server); } } public static void addListener(NodeCache nodeCache){ //监听类型:节点是否存在,节点数据内容改变,不监听节点删除。 nodeCache.getListenable().addListener(new NodeCacheListener(){ @Override public void nodeChanged() throws Exception { // TODO Auto-generated method stub if(nodeCache.getCurrentData()!=null) System.out.println("path:"+nodeCache.getCurrentData().getPath()+",data:"+new String(nodeCache.getCurrentData().getData())); }}); } }
在上面的代码中首先创建了一个节点,然后创建用这个节点路径来创建NodeCache,启动NodeCache,添加NodeCacheListener。然后调用setData来修改节点数据。上面的代码输入如下:
path:/francis/nodecache/_c_d5be73ca-592c-4eda-b7c4-c8ec60ef39a8-a,data:hello
子节点监听:
PathChildrenCache的构造函数如下:
public PathChildrenCache(CuratorFramework client, String path, boolean cacheData) Parameters: client - the client path - path to watch cacheData - if true, node contents are cached in addition to the stat
其中最主要的是cacheData,如果为true,那么当对子节点调用setData时,PathChildrenCache会受到这个CHILD_UPDATED事件。
下面看一下demo:
package cn.francis.maven.hello.ZooKeeper; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.cache.NodeCache; import org.apache.curator.framework.recipes.cache.NodeCacheListener; import org.apache.curator.framework.recipes.cache.PathChildrenCache; import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener; import org.apache.curator.framework.recipes.cache.TreeCache; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.test.TestingServer; import org.apache.curator.utils.CloseableUtils; import org.apache.curator.utils.ZKPaths; import org.apache.hadoop.mapred.join.Parser.TType; import org.apache.zookeeper.CreateMode; public class NodeCacheDemo { public static void main(String[]args) throws Exception{ TestingServer server=null; CuratorFramework client=null; NodeCache nodeCache=null; String path="/francis/nodecache/b"; try{ server=new TestingServer(); client= CuratorFrameworkFactory.newClient(server.getConnectString(),new ExponentialBackoffRetry(1000,3)); client.start(); //这里将第三个参数cacheData设置为true,这样当对子节点调用setData时,会受到CHILDREN_UPDATE通知。 PathChildrenCache childrenCache=new PathChildrenCache(client,path,true);
childrenCache.start(StartMode.POST_INITIALIZED_EVENT); childrenCache.getListenable().addListener(new PathChildrenCacheListener(){ @Override public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception { // TODO Auto-generated method stub if(event.getType()==Type.INITIALIZED){ System.out.println("create"+event.getData().getPath()); }else if(event.getType()==Type.CHILD_ADDED){ System.out.println("create"+event.getData().getPath()); }else if(event.getType()==Type.CHILD_REMOVED){ System.out.println("remove:"+event.getData().getPath()); }else if(event.getType()==Type.CHILD_UPDATED){ //System.out.println("update:"+event.getData().getPath()); System.out.println("update:"+new String(event.getData().getData())); } }}); //创建父节点 System.out.println(client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path,"init".getBytes())); Thread.sleep(1000); //创建子节点 String childPath1=ZKPaths.makePath(path, "a"); childPath1=client.create().withMode(CreateMode.PERSISTENT).forPath(childPath1,"1".getBytes()); Thread.sleep(1000); //对子节点赋值 client.setData().forPath(childPath1,"aaa".getBytes()); Thread.sleep(1000); //删除子节点 client.delete().forPath(childPath1); client.delete().deletingChildrenIfNeeded().forPath("/francis"); Thread.sleep(2000); }catch(Exception e){ e.printStackTrace(); }finally{ CloseableUtils.closeQuietly(nodeCache); CloseableUtils.closeQuietly(client); CloseableUtils.closeQuietly(server); } }
3.TreeNodeCache
TreeNodeCache将NodeCache和PathChildrenCache功能结合到一起了。他不仅可以对子节点和父节点同时进行监听。如下:
package cn.francis.maven.hello.ZooKeeper; import java.util.Map; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.cache.ChildData; import org.apache.curator.framework.recipes.cache.NodeCache; import org.apache.curator.framework.recipes.cache.NodeCacheListener; import org.apache.curator.framework.recipes.cache.PathChildrenCache; import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener; import org.apache.curator.framework.recipes.cache.TreeCache; import org.apache.curator.framework.recipes.cache.TreeCacheEvent; import org.apache.curator.framework.recipes.cache.TreeCacheListener; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent.Type; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.curator.test.TestingServer; import org.apache.curator.utils.CloseableUtils; import org.apache.curator.utils.ZKPaths; import org.apache.hadoop.mapred.join.Parser.TType; import org.apache.zookeeper.CreateMode; public class NodeCacheDemo { public static void main(String[]args) throws Exception{ TestingServer server=null; CuratorFramework client=null; NodeCache nodeCache=null; String path="/francis/nodecache/b"; try{ server=new TestingServer(); client= CuratorFrameworkFactory.newClient(server.getConnectString(),new ExponentialBackoffRetry(1000,3)); client.start(); TreeCache treeNodeCache=new TreeCache(client,path); treeNodeCache.start(); treeNodeCache.getListenable().addListener(new TreeCacheListener(){ @Override public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception { // TODO Auto-generated method stub switch(event.getType()){ case NODE_ADDED: System.out.println("added:"+event.getData().getPath()); break; case NODE_UPDATED: System.out.println("updated:"+event.getData().getPath()); break; case NODE_REMOVED: System.out.println("removed:"+event.getData().getPath()); break; default: System.out.println("other:"+event.getType()); } } }); //创建父节点 client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).forPath(path,"init".getBytes()); Thread.sleep(1000); //创建子节点 String childPath1=ZKPaths.makePath(path, "a"); childPath1=client.create().withMode(CreateMode.PERSISTENT).forPath(childPath1,"1".getBytes()); Thread.sleep(1000); //对子节点赋值 client.setData().forPath(childPath1,"aaa".getBytes()); Thread.sleep(1000); //对子节点赋值 client.setData().forPath(path,"aaa".getBytes()); Thread.sleep(1000); //删除子节点 client.delete().forPath(childPath1); client.delete().deletingChildrenIfNeeded().forPath("/francis"); Thread.sleep(2000); }catch(Exception e){ e.printStackTrace(); }finally{ //这里因为是测试,没有加他们。 CloseableUtils.closeQuietly(nodeCache); CloseableUtils.closeQuietly(client); CloseableUtils.closeQuietly(server); } } }
输出如下:
other:INITIALIZED
added:/francis/nodecache/b
added:/francis/nodecache/b/a
updated:/francis/nodecache/b/a
updated:/francis/nodecache/b
removed:/francis/nodecache/b/a
removed:/francis/nodecache/b