Java connection to zookeeper

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:

  1. 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.
  2. Watcher: Watcher is a callback interface of ZooKeeper. When the node changes, the corresponding method will be called to notify.
  3. CreateMode: The CreateMode enumeration class defines the types of nodes, including permanent nodes, temporary nodes, sequential nodes and temporary sequential nodes.
  4. 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.