API
ZooKeeper officially provides a Java API, which can be connected to the zookeeper service for operation through Java code. You can connect, create nodes, obtain node data, monitor node changes and other operations. Specifically, there are the following important classes:
- ZooKeeper: The ZooKeeper class is the core class of the Java API, used to establish a connection with the ZooKeeper server, and provides a series of methods to operate ZooKeeper nodes.
- Watcher: Watcher is a callback interface of ZooKeeper. When the node changes, the corresponding method will be called to notify.
- CreateMode: The CreateMode enumeration class defines the types of nodes, including permanent nodes, temporary nodes, sequential nodes and temporary sequential nodes.
- Stat: The Stat class represents the metadata information of the node, such as modified version, data length, number of child nodes, etc.
Add dependencies
<dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.7.2</version> </dependency>
Operation example
String host = "localhost:2181"; //establish connection zooKeeper = new ZooKeeper(host, 2000, null); String path = "/test"; Watcher watcher = new Watcher() {<!-- --> @Override public void process(WatchedEvent watchedEvent) {<!-- --> System.out.println("Node changed: " + watchedEvent.getPath()); System.out.println(watchedEvent); } }; //Get the node status. If it does not exist, return null. Stat stat = zooKeeper.exists(path, false); if(null != stat){<!-- --> System.out.println(stat.getCzxid() + "-" + stat.getAversion()); } //Create node containing information such as version, time, data length, etc. zooKeeper.create(path,"123".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); //Add watcher zooKeeper.addWatch(path, watcher, AddWatchMode.PERSISTENT); //Get node data byte[] data = zooKeeper.getData(path, false, null); System.out.println(new String(data)); zooKeeper.create(path + "/1","child1".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); //Get child nodes List<String> children = zooKeeper.getChildren(path, false); System.out.println("childs size:" + children.size()); //delete child node zooKeeper.delete(path + "/1",-1); zooKeeper.close();
zkClient
zkClient encapsulates the official API of zookeeper, simplifies some tedious operations, and provides some additional functions to improve development efficiency.
Add dependencies
<dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.11</version> </dependency>
zkclient serializes node data operations. Here we first prepare a serialization class of string type. Need to implement the ZkSerializer interface
public class ZkStringSerializer implements ZkSerializer { @Override public byte[] serialize(Object o) throws ZkMarshallingError { return String.valueOf(o).getBytes(); } @Override public Object deserialize(byte[] bytes) throws ZkMarshallingError { return new String(bytes); } }
Basic operations
ZkClient zkClient = new ZkClient("localhost:2181"); //Customize serialization, otherwise an error will be reported zkClient.setZkSerializer(new ZkStringSerializer()); String path = "/test"; //Determine whether the node exists boolean exist = zkClient.exists(path); System.out.println(exist); if(!exist){<!-- -->//Create node zkClient.create(path,"123", CreateMode.PERSISTENT); } //Read node data System.out.println((String) zkClient.readData(path)); zkClient.writeData(path,"456");//Set node data System.out.println((String) zkClient.readData(path)); zkClient.delete(path);//Delete node zkClient.close();
Node change event
String path = "/test"; /** * Node change event * Only monitor the increase and decrease of nodes, not data change events */ zkClient.subscribeChildChanges(path, new IZkChildListener() {<!-- --> @Override public void handleChildChange(String parentPath, List<String> children) throws Exception {<!-- --> System.out.println("Node" + parentPath + "Changed"); System.out.println(children); } }); //Node operation, observe that handleChildChange receives the corresponding event Thread.sleep(2000); zkClient.createPersistent(path); Thread.sleep(2000); zkClient.createPersistent(path + "/child1"); Thread.sleep(2000); zkClient.writeData(path + "/child1","123"); Thread.sleep(2000); zkClient.delete(path + "/child1"); Thread.sleep(2000); zkClient.delete(path); Thread.sleep(100000);
Node data change event
String path = "/test"; /** * Node change events only detect the current node and do not perceive its child nodes. * The node is deleted or the node data changes */ zkClient.subscribeDataChanges(path, new IZkDataListener() {<!-- --> @Override public void handleDataChange(String s, Object o) throws Exception {<!-- --> System.out.println("Node:" + s + "Data becomes:" + o); } @Override public void handleDataDeleted(String s) throws Exception {<!-- --> System.out.println("Node:" + s + "Delete"); } }); Thread.sleep(2000); zkClient.createPersistent(path); Thread.sleep(2000); zkClient.createPersistent(path + "/child1"); Thread.sleep(2000); zkClient.delete(path + "/child1"); Thread.sleep(2000); zkClient.writeData(path,"123"); Thread.sleep(2000); zkClient.delete(path); Thread.sleep(100000); }
Curator
Curator is another java library that connects to zookeeper. The function is more powerful. Provides use cases for various practical scenarios such as connection retry, distributed locks, elections, queues, etc. Here is a simple usage example.
Add dependencies
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>5.1.0</version> </dependency>
curator-framework is the basic dependency. Some specific usage methods require adding different dependencies, including curator-recipes, curator-x-discovery, curator-x-async, etc.
Basic operations
//Create connection CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(1000, 3)); client.start(); String path = "/test"; client.checkExists().forPath(path);//Determine whether it exists client.create().forPath(path, "123".getBytes());//Create node byte[] data = client.getData().forPath(path);//Get data System.out.println(new String(data)); client.setData().forPath(path, "456".getBytes());//Set data client.delete().forPath(path);//Delete node client.close();
Node listening
CuratorFramework client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(1000, 3)); client.start(); String path = "/test"; NodeCache nodeCache = new NodeCache(client,path); //Add listener nodeCache.getListenable().addListener(new NodeCacheListener() {<!-- --> @Override public void nodeChanged() throws Exception {<!-- --> ChildData data = nodeCache.getCurrentData(); if (data != null) {<!-- --> System.out.println("Node changed: " + data.getPath() + ", value: " + new String(data.getData())); } else {<!-- --> System.out.println("Node deleted: " + nodeCache.getPath()); } } }); nodeCache.start(); client.create().forPath(path); client.setData().forPath(path, "123".getBytes()); client.delete().forPath(path); client.close();
NodeCache is marked @Deprecated here, and I don’t know how it was replaced. We will study it later. Start by using it simply.