Zookeeper Curator API 使用
0. 原生 ZOOKEEPER JAVA API http://www.cnblogs.com/rocky-fang/p/9030438.html
1. 概述
Curator采用cache封装对事件的监听,包括监听节点、子节点。主要有:
NodeCache、PathChildrenCache、TreeCache
2. 例子
2.1 NodeCache
监听节点本身的变化,当节点的状态发生变更后,回调NodeCacheListener
代码
package com.rocky.learn.curator; import org.apache.curator.RetryPolicy; 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.retry.ExponentialBackoffRetry; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooKeeper; import javax.xml.ws.soap.Addressing; import java.io.IOException; import java.util.concurrent.CountDownLatch; /** * @Author: rocky * @Date: Created in 2018/5/14. */ public class NodeCacheTest { private static final CountDownLatch countDownLatch = new CountDownLatch(1); private static final String ADDRESS = "10.0.40.10:2181"; private static final String PREFIX_SYNC = "/mytest-curator"; private static final String NAMESPACE = "mybase"; private static CuratorFramework client; private static NodeCache nodeCache; static { // client = CuratorFrameworkFactory.newClient(ADDRESS, 5000, 5000, // new ExponentialBackoffRetry(1000, 3)); RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3); client = CuratorFrameworkFactory.builder() .connectString(ADDRESS) .sessionTimeoutMs(5000) .connectionTimeoutMs(5000) .retryPolicy(retryPolicy) .namespace(NAMESPACE) .build(); client.start(); } private static void initCache() throws Exception { client.create().forPath(PREFIX_SYNC); client.setData().forPath(PREFIX_SYNC,"hello curator..".getBytes()); nodeCache = new NodeCache(client, PREFIX_SYNC); nodeCache.start(true); startCache(nodeCache); } private static void startCache(final NodeCache nodeCache) throws Exception { ChildData currentData = nodeCache.getCurrentData(); System.out.println("1111:" + new String(currentData.getData())); nodeCache.getListenable().addListener(new NodeCacheListener() { public void nodeChanged() throws Exception { System.out.println("data change..." + new String(nodeCache.getCurrentData().getData())); countDownLatch.countDown(); } }); Thread.sleep(2000); if(client.checkExists().forPath(PREFIX_SYNC) != null){ System.out.println("设置新内容。。。。"); client.setData().forPath(PREFIX_SYNC, "2222".getBytes()); } } public static void main(String[] args) throws Exception { initCache(); countDownLatch.await(); } }
控制台
2.2. PathChildrenCache
主要用来监听子节点,并且不会对二级节点进行监听
代码
package com.rocky.learn.curator; import org.apache.curator.RetryPolicy; 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.PathChildrenCache; import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent; import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener; import org.apache.curator.retry.ExponentialBackoffRetry; import org.apache.zookeeper.data.Stat; import java.util.concurrent.CountDownLatch; /** * @Author: rocky * @Date: Created in 2018/5/15. */ public class PathCacheTest { private static final String PATH = "/mycache/test7"; private static final String ADDRESS = "10.0.40.10:2181"; private static final String BASE = "mybase"; private static PathChildrenCache pathChildrenCache; private static CuratorFramework client; private static CountDownLatch countDownLatch = new CountDownLatch(1); private static CountDownLatch countDownLatch2 = new CountDownLatch(5); static { RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3); client = CuratorFrameworkFactory.builder() .connectString(ADDRESS) .sessionTimeoutMs(5000) .connectionTimeoutMs(5000) .retryPolicy(retryPolicy) // .namespace(BASE) .build(); client.start(); } public static void main(String[] args) throws Exception { startCache(); countDownLatch.await(); } private static void startCache() throws Exception { pathChildrenCache = new PathChildrenCache(client, PATH, true); pathChildrenCache.start(); for (int i = 1; i < 6; i++) { String newPath = PATH + "/child_" + i; String childNodeName = "child_" + i; client.create().creatingParentsIfNeeded().forPath(newPath, childNodeName.getBytes()); countDownLatch2.countDown(); } countDownLatch2.await(); addListener(pathChildrenCache); for(final ChildData childData : pathChildrenCache.getCurrentData()){ System.out.println("输出: child path :" + childData.getPath() + ", child data: " + new String(childData.getData())); } Thread.sleep(2000); System.out.println("父节点设值......start");//不会有事件监听返回 client.setData().forPath(PATH, "11111".getBytes()); System.out.println("父节点设值......end"); System.out.println("子节点 del....start"); client.delete().forPath(PATH + "/child_1"); System.out.println("子节点 del....end"); Thread.sleep(2000); for(int j=1; j<3; j++){ String newPath = PATH + "/child_2/" + j; String nodeName = "child_2_"+ j; client.create().forPath(newPath, nodeName.getBytes()); } addListener(pathChildrenCache); System.out.println("二级节点 del...start");//不会有事件监听返回 client.delete().forPath(PATH + "/child_2/2"); System.out.println("二级节点 del...end"); countDownLatch.countDown(); } private static void addListener(final PathChildrenCache pathChildrenCache) { final PathChildrenCacheListener pathChildrenCacheListener = new PathChildrenCacheListener() { public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent event) throws Exception { System.out.println("listener child node path :" + event.getData().getPath() + ", child node data: " + new String(event.getData().getData())); } }; pathChildrenCache.getListenable().addListener(pathChildrenCacheListener); } }
控制台
注意:上面输出 部分监听没有触发,应该是操作频繁,可以使用sleep间隔一下。
有多个构造函数,并支持线程池回调
public PathChildrenCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, ThreadFactory threadFactory) { this(client, path, cacheData, dataIsCompressed, new CloseableExecutorService(Executors.newSingleThreadExecutor(threadFactory), true)); } public PathChildrenCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, ExecutorService executorService) { this(client, path, cacheData, dataIsCompressed, new CloseableExecutorService(executorService)); }
2.3. TreeCache
既能监听节点 也能监听子节点
代码
package com.rocky.learn.curator; import org.apache.curator.RetryPolicy; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.cache.*; import org.apache.curator.retry.ExponentialBackoffRetry; import java.util.concurrent.CountDownLatch; /** * @Author: rocky * @Date: Created in 2018/5/15. */ public class TreeCacheTest { private static final String PATH = "/mytreecache/test"; private static final String ADDRESS = "10.0.40.10:2181"; private static TreeCache treeCache; private static CuratorFramework client; private static CountDownLatch countDownLatch = new CountDownLatch(1); static { RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3); client = CuratorFrameworkFactory.builder() .connectString(ADDRESS) .sessionTimeoutMs(5000) .connectionTimeoutMs(5000) .retryPolicy(retryPolicy) // .namespace(BASE) .build(); client.start(); } public static void main(String[] args) throws Exception { startCache(); countDownLatch.await(); } private static void startCache() throws Exception { treeCache = new TreeCache(client, PATH); treeCache.start(); addListener(); for (int i = 1; i < 4; i++) { String newPath = PATH + "/child_" + i; String childNodeName = "child_" + i; client.create().creatingParentsIfNeeded().forPath(newPath, childNodeName.getBytes()); } Thread.sleep(2000); client.setData().forPath(PATH, "change Papa Data first time".getBytes()); Thread.sleep(2000); if(null != client.checkExists().forPath(PATH)) client.setData().forPath(PATH + "/child_1", "change son Data first time".getBytes()); Thread.sleep(2000); client.setData().forPath(PATH, "change Papa Data second time".getBytes()); Thread.sleep(2000); countDownLatch.countDown(); } private static void addListener() { treeCache.getListenable().addListener(new TreeCacheListener() { public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception { System.out.println("node change...data>>" + new String(treeCacheEvent.getData().getData())); } }); } }
控制台
只要节点发生变化,监听事件就回执行回调,不论父节点还是子节点,且不用反复注册。
2.4 ConnectionStateListener
代码
client.getConnectionStateListenable().addListener(new ConnectionStateListener() { public void stateChanged(CuratorFramework curatorFramework, ConnectionState state) { if(state == ConnectionState.CONNECTED){ System.out.println("zk connected.."); }else if(state == ConnectionState.LOST){ System.out.println("zk session lost.."); }else if(state == ConnectionState.RECONNECTED){ System.out.println("zk reconnected.."); } } });
ConnectionStateListener监控连接的状态,当连接状态为LOST,curator-recipes下的所有Api将会失效或者过期
2.5 close
用完后最好关闭 cache和 client(CuratorFramework)
cache.close(); client.close()