ZkClient 是git上一个开源的Zookeeper客户端,ZkClient 在 Zookeeper 原生API接口的基础上进行了包装,是一个更加易用的Zookeeper客户端。同时,ZkClient在内部实现了 Session 超时重连、Watchar 反复注册等功能。

引入jar包

    <dependency>
      <groupId>org.apache.zookeeper</groupId>
      <artifactId>zookeeper</artifactId>
      <version>3.4.6</version>
    </dependency>    
    <dependency>
      <groupId>com.101tec</groupId>
      <artifactId>zkclient</artifactId>
      <version>0.5</version>
    </dependency>   

 

ZkClient 的构造函数

public ZkClient(String zkServers, int sessionTimeout, int connectionTimeout, 
ZkSerializer zkSerializer, long operationRetryTimeout){ this(new ZkConnection(zkServers, sessionTimeout), connectionTimeout, zkSerializer, operationRetryTimeout); }

 需要注意的是 ,ZkSerializer   是一个序列化器,对应 java 中的序列化器 是 SerializableSerializer

/*    */ public class SerializableSerializer
/*    */   implements ZkSerializer
/*    */ {
/*    */   public Object deserialize(byte[] bytes)
/*    */     throws ZkMarshallingError
/*    */   {
/*    */     try
/*    */     {
/* 31 */       ObjectInputStream inputStream = new TcclAwareObjectIputStream(new ByteArrayInputStream(bytes));
/* 32 */       return inputStream.readObject();
/*    */     }
/*    */     catch (ClassNotFoundException e) {
/* 35 */       throw new ZkMarshallingError("Unable to find object class.", e);
/*    */     } catch (IOException e) {
/* 37 */       throw new ZkMarshallingError(e);
/*    */     }
/*    */   }
/*    */   
/*    */   public byte[] serialize(Object serializable) throws ZkMarshallingError
/*    */   {
/*    */     try {
/* 44 */       ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
/* 45 */       ObjectOutputStream stream = new ObjectOutputStream(byteArrayOS);
/* 46 */       stream.writeObject(serializable);
/* 47 */       stream.close();
/* 48 */       return byteArrayOS.toByteArray();
/*    */     } catch (IOException e) {
/* 50 */       throw new ZkMarshallingError(e);
/*    */     }
/*    */   }
/*    */ }
View Code

使用,

创建节点, Persistent  表示持久的, Ephemeral  临时节点

 

 其中,

 public void createPersistent(String path, boolean createParents, List<ACL> acl)...

 

ZkClient zc = new ZkClient("47.112.208.150:2181",10000,10000,new SerializableSerializer());
User user = new User();
user.setId(1);
user.setName("test");
String path = zc.create("/jike5", user, CreateMode.PERSISTENT);
zc.create(path, data, acl, mode);

读节点

public <T> T readData(String path)

public <T> T readData(String path, boolean returnNullIfPathNotExists)

public <T> T readData(String path, Stat stat)

protected <T> T readData(final String path, final Stat stat, final boolean watch)

子节点,返回的是 List集合,再根据节点名 readData 

 public List<String> getChildren(String path) {
    return getChildren(path, hasListeners(path));
 }

 protected List<String> getChildren(final String path, final boolean watch) {
   (List)retryUntilConnected(new Callable(){
        public List<String> call() throws Exception {
            return _connection.getChildren(path, watch);
        }
    });
 }

 

节点是否存在

 public boolean exists(String path) 

protected boolean exists(final String path, final boolean watch)

 

删除节点(递归删除)

public boolean deleteRecursive(String path)

 

更新节点

 public void writeData(String path, Object object) 

 public void writeData(String path, Object datat, int expectedVersion)

 public Stat writeDataReturnStat(final String path, Object datat, final int expectedVersion)

 

事件订阅

1、节点发生变化

调用subscribeDataChanges方法,需要 IZkDataListener  接口的实例。
 public void subscribeDataChanges(String path, IZkDataListener listener)
{
     synchronized (_dataListener) {
       Set<IZkDataListener> listeners = (Set)_dataListener.get(path);
       if (listeners == null) {
         listeners = new CopyOnWriteArraySet();
         _dataListener.put(path, listeners);
       }
       listeners.add(listener);
    }
     watchForData(path);
     LOG.debug("Subscribed data changes for " + path);
   }

 

public interface IZkDataListener {
    // 节点变化
    public void handleDataChange(String dataPath, Object data) throws Exception;
    // 节点删除
    public void handleDataDeleted(String dataPath) throws Exception;
}

 

2、子节点发生变化

调用subscribeChildChanges方法,需要 IZkChildListener 接口的实例。监听的节点可以不存在
 public List<String> subscribeChildChanges(String path, IZkChildListener listener) {
 synchronized (_childListener) {
   Set<IZkChildListener> listeners = (Set)_childListener.get(path);
   if (listeners == null) {
     listeners = new CopyOnWriteArraySet();
     _childListener.put(path, listeners);
     }
   listeners.add(listener);
   }
 return watchForChilds(path);
 }

 

public interface IZkChildListener {

    public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception;
}

 

关于序列化器

SerializableSerializer
 public class SerializableSerializer
   implements ZkSerializer
 {
   public Object deserialize(byte[] bytes)
     throws ZkMarshallingError
   {
     try
     {
       ObjectInputStream inputStream = new TcclAwareObjectIputStream(new ByteArrayInputStream(bytes));
      return inputStream.readObject();
     }
     catch (ClassNotFoundException e) {
       throw new ZkMarshallingError("Unable to find object class.", e);
     } catch (IOException e) {
       throw new ZkMarshallingError(e);
     }
   }
   
   public byte[] serialize(Object serializable) throws ZkMarshallingError
   {
     try {
       ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
       ObjectOutputStream stream = new ObjectOutputStream(byteArrayOS);
       stream.writeObject(serializable);
       stream.close();
       return byteArrayOS.toByteArray();
     } catch (IOException e) {
       throw new ZkMarshallingError(e);
     }
   }
 }

 

 

 BytesPushThroughSerializer 序列化器

ZkClient zc = new ZkClient("47.112.208.150:2181",10000,10000,new BytesPushThroughSerializer());
public class BytesPushThroughSerializer implements ZkSerializer {

    @Override
    public Object deserialize(byte[] bytes) throws ZkMarshallingError {
        return bytes;
    }

    @Override
    public byte[] serialize(Object bytes) throws ZkMarshallingError {
        return (byte[]) bytes;
    }

}