ZooKeeper Watch Java API浅析exists

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介:         Watch是ZooKeeper中非常重要的一个机制,它可以监控ZooKeeper中节点的变化情况,告知客户端。下面,我们以代码为例来分析Watch在ZooKeeper中是如何实现的。

        Watch是ZooKeeper中非常重要的一个机制,它可以监控ZooKeeper中节点的变化情况,告知客户端。下面,我们以代码为例来分析Watch在ZooKeeper中是如何实现的。ZooKeeper中一共由三种方法可以实现Watch,分别为getData、exists和getChildren,今天我们先来看下exists()方法:

        2、exists()

import java.io.IOException;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.data.Stat;

public class TestZooKeeperWatcher {

	public static void main(String[] args) {

		ZooKeeper zk = null;
		try {

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			System.out.println("开始连接ZooKeeper...");

			// 创建与ZooKeeper服务器的连接zk
			String address = "192.168.1.226:2181";
			int sessionTimeout = 3000;
			zk = new ZooKeeper(address, sessionTimeout, new Watcher() {
				// 监控所有被触发的事件
				public void process(WatchedEvent event) {
					if (event.getType() == null || "".equals(event.getType())) {
						return;
					}
					System.out.println("已经触发了" + event.getType() + "事件!");
				}
			});

			System.out.println("ZooKeeper连接创建成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			// 创建根目录节点
			// 路径为/tmp_root_path
			// 节点内容为字符串"我是根目录/tmp_root_path"
			// 创建模式为CreateMode.PERSISTENT
			System.out.println("开始创建根目录节点/tmp_root_path...");
			zk.create("/tmp_root_path", "我是根目录/tmp_root_path".getBytes(),
					Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			System.out.println("根目录节点/tmp_root_path创建成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			// 创建第一个子目录节点
			// 路径为/tmp_root_path/childPath1
			// 节点内容为字符串"我是第一个子目录/tmp_root_path/childPath1"
			// 创建模式为CreateMode.PERSISTENT
			System.out.println("开始创建第一个子目录节点/tmp_root_path/childPath1...");
			zk.create("/tmp_root_path/childPath1",
					"我是第一个子目录/tmp_root_path/childPath1".getBytes(),
					Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			System.out.println("第一个子目录节点/tmp_root_path/childPath1创建成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			// 创建第二个子目录节点
			// 路径为/tmp_root_path/childPath2
			// 节点内容为字符串"我是第二个子目录/tmp_root_path/childPath2"
			// 创建模式为CreateMode.PERSISTENT
			System.out.println("开始创建第二个子目录节点/tmp_root_path/childPath2...");
			zk.create("/tmp_root_path/childPath2",
					"我是第二个子目录/tmp_root_path/childPath2".getBytes(),
					Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
			System.out.println("第二个子目录节点/tmp_root_path/childPath2创建成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			// 修改第一个子目录节点/tmp_root_path/childPath1数据
			System.out.println("开始修改第一个子目录节点/tmp_root_path/childPath1数据...");
			zk.setData("/tmp_root_path/childPath1",
					"我是修改数据后的第一个子目录/tmp_root_path/childPath1".getBytes(), -1);
			System.out.println("修改第一个子目录节点/tmp_root_path/childPath1数据成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			// 修改第二个子目录节点/tmp_root_path/childPath2数据
			System.out.println("开始修改第二个子目录节点/tmp_root_path/childPath2数据...");
			zk.setData("/tmp_root_path/childPath2",
					"我是修改数据后的第二个子目录/tmp_root_path/childPath2".getBytes(), -1);
			System.out.println("修改第二个子目录节点/tmp_root_path/childPath2数据成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			
			// 获取根目录节点状态
			System.out.println("开始获取根目录节点状态...");
			System.out.println(zk.exists("/tmp_root_path", true));
			System.out.println("根目录节点状态获取成功");

			Thread.currentThread().sleep(1000l);
			
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			
			// 删除第一个子目录节点
			System.out.println("开始删除第一个子目录节点/tmp_root_path/childPath1...");
			zk.delete("/tmp_root_path/childPath1", -1);
			System.out.println("第一个子目录节点/tmp_root_path/childPath1删除成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			// 删除第二个子目录节点
			System.out.println("开始删除第二个子目录节点/tmp_root_path/childPath2...");
			zk.delete("/tmp_root_path/childPath2", -1);
			System.out.println("第二个子目录节点/tmp_root_path/childPath2删除成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

			// 删除根目录节点
			System.out.println("开始删除根目录节点/tmp_root_path...");
			zk.delete("/tmp_root_path", -1);
			System.out.println("根目录节点/tmp_root_path删除成功!");

			Thread.currentThread().sleep(1000l);

			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");

		} catch (IOException | KeeperException | InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 关闭连接
			if (zk != null) {
				try {
					zk.close();
					System.out.println("释放ZooKeeper连接成功!");

				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}

	}
}
        执行结果如下:

...
...
...
...
开始连接ZooKeeper...
ZooKeeper连接创建成功!
已经触发了None事件!
...
...
...
...
开始创建根目录节点/tmp_root_path...
根目录节点/tmp_root_path创建成功!
...
...
...
...
开始创建第一个子目录节点/tmp_root_path/childPath1...
第一个子目录节点/tmp_root_path/childPath1创建成功!
...
...
...
...
...
...
...
...
开始创建第二个子目录节点/tmp_root_path/childPath2...
第二个子目录节点/tmp_root_path/childPath2创建成功!
...
...
...
...
开始修改第一个子目录节点/tmp_root_path/childPath1数据...
修改第一个子目录节点/tmp_root_path/childPath1数据成功!
...
...
...
...
开始修改第二个子目录节点/tmp_root_path/childPath2数据...
修改第二个子目录节点/tmp_root_path/childPath2数据成功!
...
...
...
...
开始获取根目录节点状态...
2007741,2007741,1458963342014,1458963342014,0,2,0,0,29,2,2007743

根目录节点状态获取成功
...
...
...
...
开始删除第一个子目录节点/tmp_root_path/childPath1...
第一个子目录节点/tmp_root_path/childPath1删除成功!
...
...
...
...
开始删除第二个子目录节点/tmp_root_path/childPath2...
第二个子目录节点/tmp_root_path/childPath2删除成功!
...
...
...
...
开始删除根目录节点/tmp_root_path...
已经触发了NodeDeleted事件!
根目录节点/tmp_root_path删除成功!
...
...
...
...
释放ZooKeeper连接成功!
        而如果我们在获取根目录节点状态之后,修改根目录数据,添加代码和执行结果如下:

			// 修改根目录节点数据
			System.out.println("开始修改根目录节点/tmp_root_path数据...");
			zk.setData("/tmp_root_path",
					"我是修改数据后的根目录/tmp_root_path".getBytes(), -1);
			System.out.println("修改根目录节点/tmp_root_path数据成功!");
			
			Thread.currentThread().sleep(1000l);
			
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
			System.out.println("...");
...
...
...
...
开始连接ZooKeeper...
ZooKeeper连接创建成功!
已经触发了None事件!
...
...
...
...
开始创建根目录节点/tmp_root_path...
根目录节点/tmp_root_path创建成功!
...
...
...
...
开始创建第一个子目录节点/tmp_root_path/childPath1...
第一个子目录节点/tmp_root_path/childPath1创建成功!
...
...
...
...
...
...
...
...
开始创建第二个子目录节点/tmp_root_path/childPath2...
第二个子目录节点/tmp_root_path/childPath2创建成功!
...
...
...
...
开始修改第一个子目录节点/tmp_root_path/childPath1数据...
修改第一个子目录节点/tmp_root_path/childPath1数据成功!
...
...
...
...
开始修改第二个子目录节点/tmp_root_path/childPath2数据...
修改第二个子目录节点/tmp_root_path/childPath2数据成功!
...
...
...
...
开始获取根目录节点状态...
2007775,2007775,1458963528012,1458963528012,0,2,0,0,29,2,2007777

根目录节点状态获取成功
...
...
...
...
开始修改根目录节点/tmp_root_path数据...
已经触发了NodeDataChanged事件!
修改根目录节点/tmp_root_path数据成功!
...
...
...
...
开始删除第一个子目录节点/tmp_root_path/childPath1...
第一个子目录节点/tmp_root_path/childPath1删除成功!
...
...
...
...
开始删除第二个子目录节点/tmp_root_path/childPath2...
第二个子目录节点/tmp_root_path/childPath2删除成功!
...
...
...
...
开始删除根目录节点/tmp_root_path...
根目录节点/tmp_root_path删除成功!
...
...
...
...
释放ZooKeeper连接成功!
        与getData()一致!
        

        结论:
        exists()方法仅仅监控对应节点的一次数据变化,无论是数据修改还是删除!若要每次对应节点发生变化都被监测到,那么每次都得先调用exists()方法获取一遍节点状态!



相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
1天前
|
安全 Java API
java借助代理ip,解决访问api频繁导致ip被禁的问题
java借助代理ip,解决访问api频繁导致ip被禁的问题
|
3天前
|
存储 安全 Java
说说Java 8 引入的Stream API
说说Java 8 引入的Stream API
8 0
|
4天前
|
分布式计算 Java API
Java 8新特性之Lambda表达式与Stream API
【4月更文挑战第16天】本文将介绍Java 8中的两个重要新特性:Lambda表达式和Stream API。Lambda表达式是Java 8中引入的一种新的编程语法,它允许我们将函数作为参数传递给其他方法,从而使代码更加简洁、易读。Stream API是Java 8中引入的一种新的数据处理方式,它允许我们以声明式的方式处理数据,从而使代码更加简洁、高效。本文将通过实例代码详细讲解这两个新特性的使用方法和优势。
|
5天前
|
安全 Java API
RESTful API设计与实现:Java后台开发指南
【4月更文挑战第15天】本文介绍了如何使用Java开发RESTful API,重点是Spring Boot框架和Spring MVC。遵循无状态、统一接口、资源标识和JSON数据格式的设计原则,通过创建控制器处理HTTP请求,如示例中的用户管理操作。此外,文章还提及数据绑定、验证、异常处理和跨域支持。最后,提出了版本控制、安全性、文档测试以及限流和缓存的最佳实践,以确保API的稳定、安全和高效。
|
7天前
|
存储 Java 关系型数据库
掌握Java 8 Stream API的艺术:详解流式编程(一)
掌握Java 8 Stream API的艺术:详解流式编程
37 1
|
17天前
|
前端开发 Java API
构建RESTful API:Java中的RESTful服务开发
【4月更文挑战第3天】本文介绍了在Java环境中构建RESTful API的重要性及方法。遵循REST原则,利用HTTP方法处理资源,实现CRUD操作。在Java中,常用框架如Spring MVC简化了RESTful服务开发,包括定义资源、设计表示层、实现CRUD、考虑安全性、文档和测试。通过Spring MVC示例展示了创建RESTful服务的步骤,强调了其在现代Web服务开发中的关键角色,有助于提升互操作性和用户体验。
构建RESTful API:Java中的RESTful服务开发
|
26天前
|
Java 数据库连接 API
Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API
Java 是一种广泛使用的、面向对象的编程语言,始于1995年,以其跨平台性、安全性和可靠性著称,应用于从移动设备到数据中心的各种场景。基础概念包括变量(如局部、实例和静态变量)、数据类型(原始和非原始)、条件语句(if、else、switch等)、函数、循环、异常处理、数据结构(如数组、链表)和面向对象编程(类、接口、继承等)。深入学习还包括包、内存管理、集合框架、序列化、网络套接字、泛型、流、JVM、垃圾回收和线程。构建工具如Gradle、Maven和Ant简化了开发流程,Web框架如Spring和Spring Boot支持Web应用开发。ORM工具如JPA、Hibernate处理对象与数
90 3
|
8天前
|
安全 算法 Java
深入理解Java并发编程:线程安全与性能优化
【4月更文挑战第11天】 在Java中,高效的并发编程是提升应用性能和响应能力的关键。本文将探讨Java并发的核心概念,包括线程安全、锁机制、线程池以及并发集合等,同时提供实用的编程技巧和最佳实践,帮助开发者在保证线程安全的前提下,优化程序性能。我们将通过分析常见的并发问题,如竞态条件、死锁,以及如何利用现代Java并发工具来避免这些问题,从而构建更加健壮和高效的多线程应用程序。
|
1天前
|
安全 Java
java多线程(一)(火车售票)
java多线程(一)(火车售票)
|
2天前
|
安全 Java 调度
Java并发编程:深入理解线程与锁
【4月更文挑战第18天】本文探讨了Java中的线程和锁机制,包括线程的创建(通过Thread类、Runnable接口或Callable/Future)及其生命周期。Java提供多种锁机制,如`synchronized`关键字、ReentrantLock和ReadWriteLock,以确保并发访问共享资源的安全。此外,文章还介绍了高级并发工具,如Semaphore(控制并发线程数)、CountDownLatch(线程间等待)和CyclicBarrier(同步多个线程)。掌握这些知识对于编写高效、正确的并发程序至关重要。