使用org.I0Itec.zkclient创建ZkClient实例时,若不指定序列化类,会默认使用org.I0Itec.zkclient.serialize.SerializableSerializer。如果读取zk节点上的数据会出现StreamCorruptedException报错或者往zk节点上写data会出现乱码,可以考虑下重写默认序列化类。
报错图如下:
排查思路
zkclient实例创建代码如下:
public ZkClient(String zkServers, int sessionTimeout, int connectionTimeout) {
this((IZkConnection)(new ZkConnection(zkServers, sessionTimeout)), connectionTimeout);
}
再往下看会发现构造函数使用了默认的SerializableSerializer()
public ZkClient(IZkConnection connection, int connectionTimeout) {
this(connection, connectionTimeout, new SerializableSerializer());
}
类SerializableSerializer实现接口ZkSerializer。接口ZkSerializer代码如下:
public interface ZkSerializer {
//序列化,将对象转为字节码
public byte[] serialize(Object data) throws ZkMarshallingError;
//反序列化,将字节码转为对象
public Object deserialize(byte[] bytes) throws ZkMarshallingError;
}
动手开始
所以,我们定义自己的序列化类,使用UTF-8编码
public class MyZkSerializer implements ZkSerializer
{
public Object deserialize(byte[] bytes) throws ZkMarshallingError
{
return new String(bytes, Charset.forName("UTF-8"));
}
public byte[] serialize(Object obj) throws ZkMarshallingError
{
return String.valueOf(obj).getBytes(Charset.forName("UTF-8"));
}
}
创建ZkClient实例后配置序列化实现,不使用默认的构造函数
ZkClient client = new ZkClient("IP:PORT", sessionTimeout, connectionTimeout);
client.setZkSerializer(new MyZkSerializer());
这样就不会报错了~