Apache Curator被称为zookeeper客户端开发的瑞士军刀。该框架把zookeeper原生的api封装为highlevel的api,使操作zookeeper更加高效便捷。
Patrixck Hunt(Zookeeper commiter)认为Curator对zookeeper的价值就像Guava对java的价值。
ph-quote.png
Curator优点
- Curator封装了zookeeper的原生api,帮程序员屏蔽了底层细节,如果断链重连,反复注册Watcher,NodeExistsException等,极大提高了开发效率
- Curator支持事务,一个事务中的操作要么全部成功,要么全部失败
- Curator针对zookeeper的常见应用场景(如leader选举,分布式锁等)提供了代码框架(Recipes)。
基本操作代码示例
- 引入jar包
这里通过maven引入最新版本的curator-5.0.0
org.apache.curator
curator-recipes
5.0.0
- 创建会话
//重试策略,每隔1000ms重试一次,总共重试10次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 10);
client = CuratorFrameworkFactory.builder()
.connectString("127.0.0.1:2181") //zookeeper服务器地址
.retryPolicy(retryPolicy) //重试策略
.connectionTimeoutMs(30 * 1000) //连接超时时间
.sessionTimeoutMs(3 * 1000) //会话超时时间
.build();
client.start();
- 创建节点
创建空节点是可以不指定节点的值,也可以指定节点值
client.create().forPath("/myNodeWithoutData");
client.create().forPath("/myPermanentNode", "192.168.1.70".getBytes());
client.create().withMode(CreateMode.EPHEMERAL).forPath("/myTempNode", "192.168.10.20".getBytes());
client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath("/mySequentialNode", "192.168.10.21".getBytes());
- 设置节点
client.setData().forPath("/myNodeWithoutData", "192.168.0.50".getBytes());
client.create().orSetData().creatingParentContainersIfNeeded().forPath("/myParentNode/myChildNode_1", "child-1".getBytes());
client.create().orSetData().creatingParentContainersIfNeeded().forPath("/myParentNode/myChildNode_2", "child-2".getBytes());
- 获取节点存储的值
String data = new String(client.getData().forPath("/myPermanentNode"));
System.out.println(data);
List children = client.getChildren().forPath("/");
children.stream().forEach(System.out::println);
- 判断节点是否存在
Stat stat = client.checkExists().forPath("/myNodeWithoutData");
System.out.println(null == stat ? "exists" : "not exists");
- 删除节点
如果要删除一个包含字节的节点,可以使用deletingChildrenIfNeeded方法
client.delete().guaranteed().deletingChildrenIfNeeded().forPath("/myNode");
事务操作
如下示例代码中的createOp,setDataOp,deleteOp位于一个事务中,这个三个操作要么同时成功生效,要么同时失败回滚
CuratorOp createOp = client.transactionOp().create().forPath("/myNode");
CuratorOp setDataOp = client.transactionOp().setData().forPath("/myNode", "192.168.0.1".getBytes());
CuratorOp deleteOp = client.transactionOp().delete().forPath("/AAA");
List result = client.transaction().forOperations(createOp, setDataOp, deleteOp);
result.stream().forEach(rt -> System.out.println(rt.getForPath() + "---" + rt.getType()));
节点事件监听
Curator框架通过CuratorCache缓存程序指定的节点到本地,并在数据变化时通知Listener。
CuratorCacheListener监听节点及其所有子节点的创建、删除以及数据更新
try(CuratorCache cache = CuratorCache.builder(client, "/node/child").build()){
CuratorCacheListener listener = CuratorCacheListener.builder()
.forCreates(childData -> System.out.println(String.format("creating node %s", childData)))
.forChanges((oldNode, newNode) -> System.out.println(String.format("change %s to %s", oldNode, newNode)))
.forDeletes(node -> System.out.println(String.format("deleted node %s", node)))
.forInitialized(() -> System.out.println("Initialized"))
.build();
cache.listenable().addListener(listener, pool);
cache.start();
}