提示:以下是本篇文章正文内容
一、Curator介绍
- Curator是Apache ZooKeeper的Java客户端库
- 常见的ZooKeeper Java API:
原生Java API
ZkClient
Curator - Curator项目的目标是简化ZooKeeper客户端的使用。
- Curator官网
二、Curator API常用操作
1、增删改查API操作
public class CuratorTest {
private CuratorFramework client;
@Before
public void testConnect() {
/*// 第一种方式
// 四个参数:连接字符串(zkServer地址和端口)、会话超时时间,单位ms
// 连接超时时间,单位ms、重试策略(连接没有建立成功以后重试的模式)
// 第一个参数为每两次重试间隔的时间,单位为ms,第二个参数为最大重试次数
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(3000, 10);
// 中间两个参数不给的话有默认值,默认值就是我们给出的这个
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 60 * 1000,
15 * 1000, retryPolicy);
// 开启连接
client.start();*/
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(3000, 10);
// 第二种方式(链式编程)
// nameSpace命名空间,默认以后将“zkTest”作为根节点
client = CuratorFrameworkFactory.builder().connectString("localhost:2181").sessionTimeoutMs(60 * 1000).
connectionTimeoutMs(15 * 1000).retryPolicy(retryPolicy).namespace("zkTest").build();
// 开启连接
client.start();
}
/**
* 创建节点:create 持久 临时 顺序 数据
* 将命令行操作还原成代码
* 1、基本创建
* 2、创建节点 带有数据
* 3、设置节点的类型
* 4、创建多级节点
*/
@Test
public void testCreate1() throws Exception {
// 1、基本创建
// 如果创建节点,没有指定数据,则默认将当前客户端的ip作为数据存储
java.lang.String path = client.create().forPath("/app1");
System.out.println(path);
}
@Test
public void testCreate2() throws Exception {
// 2、创建节点 带有数据
java.lang.String path = client.create().forPath("/app2", "hehe".getBytes());
System.out.println(path);
}
@Test
public void testCreate3() throws Exception {
// 3、设置节点的类型
// 默认类型:持久化
// 创建临时节点,当前会话结束,节点就会被删除
java.lang.String path = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3", "hehe".getBytes());
System.out.println(path);
}
@Test
public void testCreate4() throws Exception {
// 4、创建多级节点
// creatingParentsIfNeeded():如果父节点不存在,则创建父节点
java.lang.String path = client.create().creatingParentsIfNeeded().forPath("/app4/p1");
System.out.println(path);
}
// ----------------------------------------------------------------------------------------------------------
/**
* 查询节点
* 查询数据
* 查询子节点
* 查询节点状态信息: ls -s
*/
@Test
public void testGet1() throws Exception {
byte[] data = client.getData().forPath("/app1");
System.out.println(new String(data));
}
@Test
public void testGet2() throws Exception {
List<String> list = client.getChildren().forPath("/");
System.out.println(list);
}
@Test
public void testGet3() throws Exception {
Stat status = new Stat();
client.getData().storingStatIn(status).forPath("/app1");
System.out.println(status);
}
// ----------------------------------------------------------------------------------------------------------
/**
* 修改数据
* 根据版本修改
* @throws Exception
*/
@Test
public void testSet() throws Exception {
client.setData().forPath("/app1", "hello".getBytes());
}
@Test
public void testSetForVersion() throws Exception {
Stat status = new Stat();
client.getData().storingStatIn(status).forPath("/app1");
int version = status.getVersion();
System.out.println(version);
client.setData().withVersion(version).forPath("/app1", "haha".getBytes());
}
// ----------------------------------------------------------------------------------------------------------
@Test
public void testDelete() throws Exception {
client.delete().forPath("/app1");
}
@Test
public void testDelete2() throws Exception {
// 删除带有子节点的节点
client.delete().deletingChildrenIfNeeded().forPath("/app4");
}
@Test
public void testDelete3() throws Exception {
// 必须成功的删除
client.delete().guaranteed().forPath("/app2");
}
@Test
public void testDelete4() throws Exception {
// 回调
client.delete().guaranteed().inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
System.out.println("我被删除了");
System.out.println(curatorEvent);
}
}).forPath("/app1");
}
@After
public void close() {
if(client != null) {
client.close();
}
}
}
-测试工程中的POM文件需要添加以下依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<!--curator-->
<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>
<!--日志-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
2、watch事件监听
- zookeeper允许用户在指定节点上注册一些watcher,并且在一些特定事件触发的时候,zookeeper服务端会将事件通知到感兴趣的客户端上去,该机制是zookeeper实现分布式协调服务的重要特性。
- 引入了watch机制实现了发布/订阅功能,能够让多个订阅者同时监听某一个对象,当一个对象自身状态变化时,会通知所有订阅者。
- 原生支持通过注册watcher来进行事件监听,但是其使用并不是特别方便需要开发人员自己反复注册watcher,比较繁琐。
- curator引入了Cache来实现对zookeeper服务端事件的监听。
- 提供了三种Watcher
NodeCache:只是监听某一个特定的节点。
PathChildrenCache:监控一个ZNode的子节点。
TreeChe:可以监听整个树上的所有节点,类似于PathChildrenChe和NodeCache的组合。 - 下面是具体的演示过程:
package org.example.curator;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import javax.xml.soap.Node;
import java.util.List;
public class CuratorWatcherTest {
private CuratorFramework client;
@Before
public void testConnect() {
/*// 第一种方式
// 四个参数:连接字符串(zkServer地址和端口)、会话超时时间,单位ms
// 连接超时时间,单位ms、重试策略(连接没有建立成功以后重试的模式)
// 第一个参数为每两次重试间隔的时间,单位为ms,第二个参数为最大重试次数
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(3000, 10);
// 中间两个参数不给的话有默认值,默认值就是我们给出的这个
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", 60 * 1000,
15 * 1000, retryPolicy);
// 开启连接
client.start();*/
ExponentialBackoffRetry retryPolicy = new ExponentialBackoffRetry(3000, 10);
// 第二种方式(链式编程)
// nameSpace命名空间,默认以后将“zkTest”作为根节点
client = CuratorFrameworkFactory.builder().connectString("localhost:2181").sessionTimeoutMs(60 * 1000).
connectionTimeoutMs(15 * 1000).retryPolicy(retryPolicy).namespace("zkTest").build();
// 开启连接
client.start();
}
/**
* 演示NodeChe:给指定一个节点注册监听器
*/
@Test
public void testNodeChe() throws Exception {
// 1、创建NodeCache对象 jdk版本是不用加final的
final NodeCache nodeCache = new NodeCache(client, "/app4");
// 2、注册监听
nodeCache.getListenable().addListener(new NodeCacheListener() {
@Override
public void nodeChanged() throws Exception {
System.out.println("节点变化了……");
//获取修改节点后的数据
byte[] data = nodeCache.getCurrentData().getData();
System.out.println(new String(data));
}
});
nodeCache.start();
// 使方法一直执行,如果是真实场景,不用这么写,因为用的是线程
while(true) {
}
}
/**
* 演示PathChildrenCache:监听某个节点的所有子节点们
* 但是感知不到当前节点的变化
*/
@Test
public void testPathChildrenCache() throws Exception {
// 1、创建监听对象
PathChildrenCache pathChildrenCache = new PathChildrenCache(client, "/app2", true);
// 2、绑定监听器
pathChildrenCache.getListenable().addListener(new PathChildrenCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) throws Exception {
System.out.println("子节点变化了……");
System.out.println(pathChildrenCacheEvent);
// 监听子节点的数据变更,拿到变更后的数据
// 获取类型
PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
// 判断类型是否是update
if(type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {
System.out.println("数据变了");
byte[] data = pathChildrenCacheEvent.getData().getData();
System.out.println(new String(data));
}
}
});
pathChildrenCache.start();
while (true) {
}
}
/**
* 演示PtestTreeCache:监听某个节点的所有子节点们和自己
*/
@Test
public void testTreeCache() throws Exception {
// 创建监听器
TreeCache treeCache = new TreeCache(client, "/app2");
// 注册监听
treeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
System.out.println("节点变化了");
System.out.println(treeCacheEvent);
}
});
treeCache.start();
while (true) {
}
}
@After
public void close() {
if(client != null) {
client.close();
}
}
}