Java API的基本使用
添加依赖
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.7.0</version> </dependency> 复制代码
创建ZK连接
@SpringBootTest public class ZKTest { /** * 获取zookeeper连接时所需要的服务器连接信息,格式为主机名:端口号;多个服务使用“,”分割 */ public final String CONNECT_STRING = "127.0.0.1:2181"; /** * 请求会话超时时长 */ public final int SESSIONT_IMEOUT = 5000; private ZooKeeper zk; private String path = "/zk"; private String sonPath = "/zk/son"; private String value = "zk_Data"; /** * 获取ZooKeeper链接 * * @return * @throws Exception */ @Before public void getZKConnection() throws Exception { zk = new ZooKeeper(CONNECT_STRING, SESSIONT_IMEOUT, null); } /** * 关闭ZK连接 * * @throws InterruptedException */ @After public void closeZKConnection() throws InterruptedException { zk.close(); } } 复制代码
创建持久不带序列编号的节点
@Test public void createZKNode1() throws Exception { // 四个参数: 节点路径,节点数据,权限信息,节点的类型 zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } 复制代码
创建持久带序列编号的节点
@Test public void createZKNode2() throws Exception { // 四个参数: 节点路径,节点数据,权限信息,节点的类型 zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); } 复制代码
创建临时不带序列编号的节点
@Test public void createZKNode3() throws Exception { // 四个参数: 节点路径,节点数据,权限信息,节点的类型 zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); } 复制代码
创建临时带序列编号的节点
@Test public void createZKNode4() throws Exception { // 四个参数: 节点路径,节点数据,权限信息,节点的类型 zk.create(path, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); zk.create(path, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); zk.create(path, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); } 复制代码
查看节点数据
@Test public void getZNodeData() throws Exception { String znodeData = new String(zk.getData(path, false, null)); System.out.println("查看节点数据:" + znodeData); } 复制代码
修改节点数据
@Test public void updateZNodeData() throws Exception { String value="update_data"; zk.setData(path, value.getBytes(), -1); String newData = new String(zk.getData(path, false, null)); if (newData.equals(value)) { System.out.println("修改节点数据: " + true); } else { System.out.println("修改节点数据: " + false); } } 复制代码
判断节点是否存在
@Test public void existsZNode() throws Exception { boolean existsZNode = (zk.exists(path, false) != null) ? true : false; System.out.println("判断节点是否存在: " + existsZNode); } 复制代码
查看节点的子节点列表
@Test public void getChildrenZNodes() throws Exception { zk.create(sonPath, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); List<String> children = zk.getChildren(path, false); for (String child : children) { System.out.println("查看节点的子节点列表: " + child); } } 复制代码
删除节点
@Test public void deleteZNode() { try { zk.delete(path, -1); } catch (InterruptedException e) { e.printStackTrace(); } catch (KeeperException e) { e.printStackTrace(); } System.out.println("删除znode节点成功"); } 复制代码
级联删除节点
@Test public void deleteAllNode() throws Exception { zk.create(path, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); zk.create(sonPath, value.getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); this.deleteAllNode(this.path); } /** * 删除一个节点,不管有有没有任何子节点 * * @return * @throws Exception */ public void deleteAllNode(String path) throws Exception { if (zk.exists(path, null) == null) { System.out.println("该路径 " + path + " 不存在"); } List<String> children = zk.getChildren(path, null); if (children.size() == 0) { zk.delete(path, -1); } else { // 删除child路径下的所有子节点,但是并不删除child节点 for (String child : children) { String deletePath = path + "/" + child; deleteAllNode(deletePath); } // 节点所有子节点删除之后,直接当前节点 zk.delete(path, -1); } } 复制代码
级联创建节点
@Test public void createAllNode() throws Exception { this.createAllNode(this.sonPath); } /** * 级联创建任意节点 * * @throws Exception */ public boolean createAllNode(String znodePath) throws Exception { // 判断该节点是否存在,如果存在,则不创建 if (zk.exists(znodePath, null) != null) { return false; } else { try { // 直接创建,捕捉异常,根据对应的异常如果是发现没有父节点,那么就创建父节点 zk.create(znodePath, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } catch (KeeperException e) { // 截取父节点 String parentPath = znodePath.substring(0, znodePath.lastIndexOf("/")); // 创建父节点 createAllNode(parentPath); try { // 父节点创建好后,创建该节点 zk.create(znodePath, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } catch (KeeperException e1) { e1.printStackTrace(); } catch (InterruptedException e1) { e1.printStackTrace(); } } catch (InterruptedException e) { e.printStackTrace(); } } return true; } 复制代码
清空子节点
@Test public void clearChildNode() throws Exception { this.clearChildNode(this.path); } /** * 清空子节点 * * @throws Exception */ public boolean clearChildNode(String path) throws Exception { List<String> children = zk.getChildren(path, null); for (String child : children) { String childNode = path + "/" + child; if (zk.getChildren(childNode, null).size() != 0) { clearChildNode(childNode); } zk.delete(childNode, -1); } return true; } 复制代码
实现节点监听
ZooKeeper可以作为注册中心,原因就在于其可以实现节点监听。
比如:在分布式系统中,一个服务启动后就可以向ZK注册中心的某个节点注册,记录服务器的信息,服务下线则删除节点下记录的服务器信息。
创建监听节点
private String sonPath = "/watch_zk/son"; private String value = "zk_Data"; private String watchPath = "/watch_zk"; @Test public void createWatchNode() throws Exception { zk.create(watchPath, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } 复制代码
实现监听
public class ZKWatch { /** * 获取zookeeper连接时所需要的服务器连接信息,格式为主机名:端口号;多个服务使用“,”分割 */ public static final String CONNECT_STRING = "127.0.0.1:2181"; /** * 请求会话超时时长 */ public static final int SESSIONT_IMEOUT = 5000; private static ZooKeeper zk; public static void main(String[] args) throws IOException, InterruptedException, KeeperException { String watchPath = "/watch_zk"; zk = new ZooKeeper(CONNECT_STRING, SESSIONT_IMEOUT, new Watcher() { @Override public void process(WatchedEvent event) { // 事件类型 Event.EventType type = event.getType(); // 节点路径 String path = event.getPath(); System.out.println("节点路径 = " + path+" 事件类型 = " + type); try { // 注册监听 节点的数据变化 // 事件: NodeDeleted, NodeDataChanged // 触发: delete, setData zk.getData(watchPath, true, null); // 注册监听 子节点个数变化 // 事件: NodeChildrenChanged, NodeDeleted // 触发: create/delete子节点, delete当前给定节点 zk.getChildren(watchPath, true); // 注册监听 该节点的变化(被创建,被删除,数据被改变) // 事件: NodeCreated, NodeDeleted, NodeDataChanged // 触发: create, delete, setData zk.exists(watchPath, true); } catch (Exception e) { e.printStackTrace(); } // 根据监听的相应的事件类型和节点,编写对应业务逻辑 if (type == Event.EventType.NodeDeleted && event.getPath().equals(watchPath)) { System.out.println("节点的数据变化---删除"); } else if (type == Event.EventType.NodeDataChanged) { System.out.println("节点的数据变化---修改"); } else if (type == Event.EventType.NodeCreated) { System.out.println("节点的数据变化---创建"); } else if (type == Event.EventType.NodeChildrenChanged) { System.out.println("子节点个数变化---创建/删除"); } else if (type == Event.EventType.NodeDeleted) { System.out.println("子节点个数变化---删除"); } } }); // 判断监听节点是否,不存在则创建 if (zk.exists(watchPath, null) == null) { zk.create(watchPath, "watchData".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } // 保证watcer线程一直工作 Thread.sleep(Long.MAX_VALUE); // 启动监听就不会关闭zk链接 // zk.close(); } } 复制代码
执行测试
@Test public void createZKNode() throws Exception { zk.setData(watchPath,value.getBytes(),-1); zk.create(sonPath, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); zk.setData(sonPath,value.getBytes(),-1); zk.delete(sonPath,-1); } 复制代码
15:31:05.201 [main] INFO org.apache.zookeeper.ZooKeeper - Initiating client connection, connectString=127.0.0.1:2181 sessionTimeout=5000 watcher=com.example.demo.zk.ZKWatch$1@23e028a9 15:31:05.206 [main] INFO org.apache.zookeeper.common.X509Util - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation 15:31:05.576 [main] INFO org.apache.zookeeper.ClientCnxnSocket - jute.maxbuffer value is 1048575 Bytes 15:31:05.618 [main] INFO org.apache.zookeeper.ClientCnxn - zookeeper.request.timeout value is 0. feature enabled=false 15:31:05.624 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.SaslServerPrincipal - Canonicalized address to activate.navicat.com 15:31:05.625 [main-SendThread(127.0.0.1:2181)] INFO org.apache.zookeeper.ClientCnxn - Opening socket connection to server activate.navicat.com/127.0.0.1:2181. 15:31:05.626 [main-SendThread(127.0.0.1:2181)] INFO org.apache.zookeeper.ClientCnxn - SASL config status: Will not attempt to authenticate using SASL (unknown error) 15:31:05.627 [main-SendThread(127.0.0.1:2181)] INFO org.apache.zookeeper.ClientCnxn - Socket connection established, initiating session, client: /127.0.0.1:2955, server: activate.navicat.com/127.0.0.1:2181 15:31:05.628 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Session establishment request sent on activate.navicat.com/127.0.0.1:2181 15:31:05.633 [main-SendThread(127.0.0.1:2181)] INFO org.apache.zookeeper.ClientCnxn - Session establishment complete on server activate.navicat.com/127.0.0.1:2181, session id = 0x1000f36f14d001b, negotiated timeout = 5000 节点路径 = null 事件类型 = None 15:31:05.638 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 1,4 replyHeader:: 1,300,0 request:: '/watch_zk,T response:: #7a6b5f44617461,s{290,295,1661412554041,1661412576797,1,2,0,0,7,0,298} 15:31:05.642 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 2,8 replyHeader:: 2,300,0 request:: '/watch_zk,T response:: v{} 15:31:05.644 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 3,3 replyHeader:: 3,300,0 request:: '/watch_zk,T response:: s{290,295,1661412554041,1661412576797,1,2,0,0,7,0,298} 15:31:07.311 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Got ping response for session id: 0x1000f36f14d001b after 0ms. 15:31:08.977 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Got ping response for session id: 0x1000f36f14d001b after 0ms. 15:31:09.104 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Got notification session id: 0x1000f36f14d001b 15:31:09.105 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Got WatchedEvent state:SyncConnected type:NodeDataChanged path:/watch_zk for session id 0x1000f36f14d001b 节点路径 = /watch_zk 事件类型 = NodeDataChanged 15:31:09.107 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 4,4 replyHeader:: 4,303,0 request:: '/watch_zk,T response:: #7a6b5f44617461,s{290,303,1661412554041,1661412669092,2,2,0,0,7,0,298} 15:31:09.108 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply session id: 0x1000f36f14d001b, packet:: clientPath:null serverPath:null finished:false header:: 5,8 replyHeader:: 5,303,0 request:: '/watch_zk,T response:: v{} 15:31:09.109 [main-SendThread(127.0.0.1:2181)] DEBUG org.apache.zookeeper.ClientCnxn - Reading reply