一、Curator介绍
curator是Apache Zookeeper的java客户端库。它的目标是简化Zookeeper客户端的使用,最初是Netfix研发,后来捐给了Apache基金会,目前是Apache的顶级项目。
有兴趣的话可以看看curator的官网:http://curator.apache.org/
二、API常用操作
注意:以下的所有代码都是在同一个测试类CuratorTest中编写!
1.建立、关闭连接
private CuratorFramework client;
public CuratorFramework getClient(){
RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
// CuratorFramework client = CuratorFrameworkFactory.newClient("122.36.96.113:2181", 60 * 1000,
// 15 * 1000, retryPolicy);
CuratorFramework client = CuratorFrameworkFactory.builder().connectString("122.36.96.113:2181")
.sessionTimeoutMs(60 * 1000)
.connectionTimeoutMs(15 * 1000)
.retryPolicy(retryPolicy)
.namespace("luzelong") //指定操作的根目录
.build();
return client;
}
/**
* 建立连接
* @Before:在所有Test方法调用前都会执行的方法
*/
@Before
public void testConnect(){
client = getClient();
client.start();
}
/**
* 关闭连接
* @After:在所有Test方法调用后都会执行的方法
*/
@After
public void close(){
if (client != null) {
client.close();
}
}
2.创建节点
@Test
public void createTest() throws Exception {
//由于client设置了namespace为luzelong,所以节点会创建在 /luzelong 下面
//1.基本创建 : 如果创建节点,没有指定数据,则默认将当前客户端的ip作为数据存储
String path1 = client.create().forPath("/app1");
//2.创建交接点带有数据
String path2 = client.create().forPath("/app2","hhhh".getBytes());
//3.设置节点的类型 , 下面的案例是创建临时节点
String path3 = client.create().withMode(CreateMode.EPHEMERAL).forPath("/app3","hhhh".getBytes());
//4.创建多级节点 /app4/p1
String path4 = client.create().creatingParentsIfNeeded().forPath("/app4/p1");
}
3.查询节点
@Test
public void testGet() throws Exception {
//1.查询数据: get
byte[] bytes = client.getData().forPath("/app1");
System.out.println(new String(bytes));
//2.查询子节点: ls
List<String> strings = client.getChildren().forPath("/app4");
System.out.println(strings);
//3.查询节点状态: ls -s
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath("/app4/p1");
System.out.println(stat);
}
4.修改节点数据
@Test
public void testSet() throws Exception {
//1.修改数据
client.setData().forPath("/app1","jjy".getBytes());
//2.根据版本修改(需要先查询版本号,CAS思想)
Stat stat = new Stat();
client.getData().storingStatIn(stat).forPath("/app2");
int version = stat.getVersion();
client.setData().withVersion(version).forPath("/app2","yy".getBytes());
}
5.删除节点
@Test
public void testDel() throws Exception {
//1.删除叶子节点 delete
client.delete().forPath("/app1");
//2.删除非叶子节点: deleteall
client.delete().deletingChildrenIfNeeded().forPath("/app4");
//3.必须成功删除
client.delete().guaranteed().forPath("/app1");
//4.带回调的删除
client.delete().inBackground(new BackgroundCallback() {
@Override
public void processResult(CuratorFramework curatorFramework, CuratorEvent curatorEvent) throws Exception {
System.out.println("我被删除了,curatorEvent="+curatorEvent);
}
}).forPath("/app1");
}
三、Watch事件监听
ZooKeeper允许用户在指定节点上注册一些Watcher,并且在一些特定事件触发的时候,ZooKeeper服务端会将事件通知到感兴趣的客户端上去,该机制是ZooKeeper实现分布式协调服务的重要特性。
ZooKeeper中引入了Watcher机制来实现了发布/订阅功能能,能够让多个订阅者同时监听某一个对象,当一个对象自身状态变化时,会通知所有订阅者。
Curator引入了Cache来实现对ZooKeeper服务端事件的监听。
zooKeeper提供了三种Watcher:
NodeCache:只是监听某一个特定的节
PathChildrenCache:监控一个ZNode的子节点.
TreeCache:可以监控整个树上的所有节点,类似于PathChildrenCache和NodeCache的组合。
1.NodeCache
@Test
public void testNodeCache() throws Exception {
//1.创建NodeCache对象
final NodeCache nodeCache = new NodeCache(client,"/app2");
//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));
}
});
//3.开启监听,如果设置为true,则开启监听加载缓存数据
nodeCache.start(true);
while (true){}
}
运行上面的代码,由于最后一行是个死循环所以程序会一直等待!这个时候其他客户端 修改|删除|创建这个节点,控制台就会执行监听事件中的方法!
如下就是利用zkCli.sh工具来模拟另一个客户端的操作行为:
2.PathChildrenCache
/**
* 演示 pathChildrenCache:监听某个节点的所有子节点们(不会监听自己)
*/
@Test
public void testPathChildren() 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);
//监听子节点的数据变更,并且拿到变更后的数据
//1.获取类型
PathChildrenCacheEvent.Type type = pathChildrenCacheEvent.getType();
//2.判断类型是否是update
if (type.equals(PathChildrenCacheEvent.Type.CHILD_UPDATED)) {
byte[] data = pathChildrenCacheEvent.getData().getData();
System.out.println("修改后子节点的数据为:" + new String(data));
}
}
});
//3.开启监听
pathChildrenCache.start();
while (true){}
}
运行上面的代码,由于最后一行是个死循环所以程序会一直等待!这个时候其他客户端在监听的节点下创建一个新的节点,控制台就会执行监听方法:
如下就是利用zkCli.sh工具来模拟另一个客户端的操作行为:
3.TreeCache
/**
* 演示TreeCache:监听某个节点自己和所有子节点们
*/
@Test
public void testTreeCache() throws Exception {
//1.创建监听对象
TreeCache treeCache = new TreeCache(client,"/app2");
//2.注册监听
treeCache.getListenable().addListener(new TreeCacheListener(){
@Override
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
System.out.println("节点变化了~~");
System.out.println(treeCacheEvent);
}
});
//3.开启
treeCache.start();
while (true){}
}
具体的演示和上面的两个基本一样,它不仅监听自己还监听它的子节点,相当于是上面两种Cache的并集
四、POM.xml文件参考
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>curator-zk</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<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.36</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.19</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>
</project>