上篇主要学习了zk的安装以及常用命令的使用,本章本介绍与常用命令对应的JavaAPI该如何使用,笔者使用Curator来操作zk,并附带亲测源码加深理解
代码地址:https://gitee.com/webprogram/springboot_zookeeper
JavaAPI操作
Curator 介绍
-
Curator是Apache Zookeeper的java客户端库
-
常见Zookeeper的JavaAPI:
- 原始javaAPI
- ZkClient
- Curator
-
Curator项目的目标是简化Zookeeper客户端的使用
-
Curator最初是Netflix研发的,后来捐献给了Apache基金会,现在是Apache的顶级项目
注意: 在引入Curator依赖时,需注意和Zookeeper的版本问题,尤其是Zookeeper3.4.X,笔者使用Zookeeper3.5.9,Curator4.0.0
附pom.xml相关依赖
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.0.0</version>
</dependency>
Curator API常用操作
Junit测试
创建链接
/**
* @description:java-api测试
*/
public class CuratorTest {
private CuratorFramework curatorClient;
/**
* @description:创建链接 两种方式
*/
@Before
public void openConnect() {
//设置重试机制,连接失败时,每隔3s重试一次,共重试3次
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 3);
//1.第一种方式
// 参数说明:连接字符串| 会话超时时间 | 连接超时时间 | 重试策略
// curatorClient = CuratorFrameworkFactory.newClient("127.0.0.1:2181", 60 * 1000, 15 * 1000, retryPolicy);
// 开启
// curatorClient.start();
// 2.第二种方式 (推荐)
curatorClient = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181")
.sessionTimeoutMs(60 * 1000)
.connectionTimeoutMs(15 * 1000)
.retryPolicy(retryPolicy)
// 设置命名空间即根目录,设置以后以后所有操作都是基于该目录下进行
// 当该节点不存在时,会自动创建
.namespace("cxu")
.build();
curatorClient.start();
}
/**
* @description:关闭资源
*/
@After
public void closeConnection() {
if (curatorClient != null) {
curatorClient.close();
}
}
}
创建节点
/**
* @description: JavaAPI 创建【create】相关
*/
@Test
public void createNode() throws Exception {
// 只创建路径而不赋值时,默认值为ip地址
//1. 创建节点
curatorClient.create().forPath("/k1");
//2. 创建节点并赋值
curatorClient.create().forPath("/k2", "v2".getBytes());
//3. 创建临时节点 CreateMode枚举中包含常见几种类型
//注:由于是临时节点,在程序结束时客户端关闭,随之临时节点消失
curatorClient.create().withMode(CreateMode.EPHEMERAL).forPath("/k3");
//4. 创建多级节点,如果父节点不存在,则自动创建
String path = curatorClient.create().creatingParentsIfNeeded().forPath("/k4/kk4");
// 测试打印出路径
System.out.println("创建路径:" + path);
}
查询节点
/**
* @description:查询节点信息
*/
@Test
public void queryNode() throws Exception {
//1. 查询节点值 get
byte[] v1 = curatorClient.getData().forPath("/k1");
System.out.println(new String(v1));
//2.查询节点信息 ls 此时‘/’等同于之前指定的namespace的值 因为指定了namespace 默认根目录就是指定值
List<String> infos = curatorClient.getChildren().forPath("/");
System.out.println(infos);
//3.查询节点状态 ls -s
Stat status = new Stat();
curatorClient.getData().storingStatIn(status).forPath("/k2");
System.out.println(status);
}
修改节点
/**
* @description:修改节点
*/
@Test
public void updateNode() throws Exception {
//1. 简单修改 set
Stat statusSingle = curatorClient.setData().forPath("/k1","vv1".getBytes());
System.out.println(statusSingle);
//2. 根据版本号修改
/**场景:在多个客户端同时修改某个值时,可能会出现预期之外的结果,所以要先获取当前节点的版本号,
如果在未修改成功之前被别的线程修改了,那么本次修改将失败
*/
//获取当前节点状态,拿到version
Stat statusBefore = new Stat();
curatorClient.getData().storingStatIn(statusBefore).forPath("/k2");
int version = statusBefore.getVersion();
//根据版本号修改
Stat statusAfter = curatorClient.setData().withVersion(version).forPath("/k2","vv2".getBytes());
System.out.println(statusAfter);
}
删除节点
/**
* @description:删除节点
*/
@Test
public void deleteNode() throws Exception {
//1.简单删除
curatorClient.delete().forPath("/k1");
//2.保证删除成功,防止网络问题导致失败,本质就是重试机制
curatorClient.delete().guaranteed().forPath("/k2");
//3.删除后回调
curatorClient.delete().guaranteed().inBackground(new BackgroundCallback() {
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
System.out.println("我被删除了");
System.out.println(curatorEvent);
}
}).forPath("/k3");
//4.删除节点及其子节点
curatorClient.delete().deletingChildrenIfNeeded().forPath("/k4");
}