一、前言

  在完成了前面的理论学习后,现在可以从源码角度来解析Zookeeper的细节,首先笔者想从序列化入手,因为在网络通信、数据存储中都用到了序列化,下面开始分析。

二、序列化

  序列化主要在zookeeper.jute包中,其中涉及的主要接口如下

    · InputArchive

    · OutputArchive

    · Index

    · Record

  2.1 InputArchive

  其是所有反序列化器都需要实现的接口,其方法如下 

public interface InputArchive {
// 读取byte类型
public byte readByte(String tag) throws IOException;
// 读取boolean类型
public boolean readBool(String tag) throws IOException;
// 读取int类型
public int readInt(String tag) throws IOException;
// 读取long类型
public long readLong(String tag) throws IOException;
// 读取float类型
public float readFloat(String tag) throws IOException;
// 读取double类型
public double readDouble(String tag) throws IOException;
// 读取String类型
public String readString(String tag) throws IOException;
// 通过缓冲方式读取
public byte[] readBuffer(String tag) throws IOException;
// 开始读取记录
public void readRecord(Record r, String tag) throws IOException;
// 开始读取记录
public void startRecord(String tag) throws IOException;
// 结束读取记录
public void endRecord(String tag) throws IOException;
// 开始读取向量
public Index startVector(String tag) throws IOException;
// 结束读取向量
public void endVector(String tag) throws IOException;
// 开始读取Map
public Index startMap(String tag) throws IOException;
// 结束读取Map
public void endMap(String tag) throws IOException;
}

  InputArchive的类结构如下

  

  1. BinaryInputArchive  

public class BinaryInputArchive implements InputArchive {
// DataInput接口,用于从二进制流中读取字节
private DataInput in; // 静态方法,用于获取Archive
static public BinaryInputArchive getArchive(InputStream strm) {
return new BinaryInputArchive(new DataInputStream(strm));
} // 内部类,对应BinaryInputArchive索引
static private class BinaryIndex implements Index {
private int nelems;
BinaryIndex(int nelems) {
this.nelems = nelems;
}
public boolean done() {
return (nelems <= 0);
}
public void incr() {
nelems--;
}
}
/** Creates a new instance of BinaryInputArchive */
// 构造函数
public BinaryInputArchive(DataInput in) {
this.in = in;
} // 读取字节
public byte readByte(String tag) throws IOException {
return in.readByte();
} // 读取boolean类型
public boolean readBool(String tag) throws IOException {
return in.readBoolean();
} // 读取int类型
public int readInt(String tag) throws IOException {
return in.readInt();
} // 读取long类型
public long readLong(String tag) throws IOException {
return in.readLong();
} // 读取float类型
public float readFloat(String tag) throws IOException {
return in.readFloat();
} // 读取double类型
public double readDouble(String tag) throws IOException {
return in.readDouble();
} // 读取String类型
public String readString(String tag) throws IOException {
// 确定长度
int len = in.readInt();
if (len == -1) return null;
byte b[] = new byte[len];
// 从输入流中读取一些字节,并将它们存储在缓冲区数组b中
in.readFully(b);
return new String(b, "UTF8");
} // 最大缓冲值
static public final int maxBuffer = Integer.getInteger("jute.maxbuffer", 0xfffff); // 读取缓冲
public byte[] readBuffer(String tag) throws IOException {
// 确定长度
int len = readInt(tag);
if (len == -1) return null;
// Since this is a rough sanity check, add some padding to maxBuffer to
// make up for extra fields, etc. (otherwise e.g. clients may be able to
// write buffers larger than we can read from disk!)
if (len < 0 || len > maxBuffer + 1024) { // 检查长度是否合理
throw new IOException("Unreasonable length = " + len);
}
byte[] arr = new byte[len];
// 从输入流中读取一些字节,并将它们存储在缓冲区数组arr中
in.readFully(arr);
return arr;
} // 读取记录
public void readRecord(Record r, String tag) throws IOException {
// 反序列化,动态调用
r.deserialize(this, tag);
} // 开始读取记录,实现为空
public void startRecord(String tag) throws IOException {} // 结束读取记录,实现为空
public void endRecord(String tag) throws IOException {} // 开始读取向量
public Index startVector(String tag) throws IOException {
// 确定长度
int len = readInt(tag);
if (len == -1) {
return null;
}
// 返回索引
return new BinaryIndex(len);
} // 结束读取向量
public void endVector(String tag) throws IOException {} // 开始读取Map
public Index startMap(String tag) throws IOException {
// 返回索引
return new BinaryIndex(readInt(tag));
} // 结束读取Map,实现为空
public void endMap(String tag) throws IOException {} }

  2. CsvInputArchive 

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.apache.jute; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PushbackReader;
import java.io.UnsupportedEncodingException; /**
*
*/
class CsvInputArchive implements InputArchive {
// 推回字节流
private PushbackReader stream; // 内部类,对应CsvInputArchive索引
private class CsvIndex implements Index {
public boolean done() {
char c = '\0';
try {
c = (char) stream.read();
stream.unread(c);
} catch (IOException ex) {
}
return (c == '}') ? true : false;
}
public void incr() {}
} // 私有方法,抛出异常
private void throwExceptionOnError(String tag) throws IOException {
throw new IOException("Error deserializing "+tag);
} // 私有方法,读取字段
private String readField(String tag) throws IOException {
try {
StringBuilder buf = new StringBuilder();
while (true) {
// 读取并转化为字符
char c = (char) stream.read();
switch (c) { // 判断字符
case ',':
// 读取字段完成,可直接返回
return buf.toString();
case '}':
case '\n':
case '\r':
// 推回缓冲区
stream.unread(c);
return buf.toString();
default: // 默认添加至buf中
buf.append(c);
}
}
} catch (IOException ex) {
throw new IOException("Error reading "+tag);
}
} // 获取CsvInputArchive
static CsvInputArchive getArchive(InputStream strm)
throws UnsupportedEncodingException {
return new CsvInputArchive(strm);
} /** Creates a new instance of CsvInputArchive */
// 构造函数
public CsvInputArchive(InputStream in)
throws UnsupportedEncodingException {
// 初始化stream属性
stream = new PushbackReader(new InputStreamReader(in, "UTF-8"));
} // 读取byte类型
public byte readByte(String tag) throws IOException {
return (byte) readLong(tag);
} // 读取boolean类型
public boolean readBool(String tag) throws IOException {
String sval = readField(tag);
return "T".equals(sval) ? true : false;
} // 读取int类型
public int readInt(String tag) throws IOException {
return (int) readLong(tag);
} // 读取long类型
public long readLong(String tag) throws IOException {
// 读取字段
String sval = readField(tag);
try {
// 转化
long lval = Long.parseLong(sval);
return lval;
} catch (NumberFormatException ex) {
throw new IOException("Error deserializing "+tag);
}
} // 读取float类型
public float readFloat(String tag) throws IOException {
return (float) readDouble(tag);
} // 读取double类型
public double readDouble(String tag) throws IOException {
// 读取字段
String sval = readField(tag);
try {
// 转化
double dval = Double.parseDouble(sval);
return dval;
} catch (NumberFormatException ex) {
throw new IOException("Error deserializing "+tag);
}
} // 读取String类型
public String readString(String tag) throws IOException {
// 读取字段
String sval = readField(tag);
// 转化
return Utils.fromCSVString(sval); } // 读取缓冲类型
public byte[] readBuffer(String tag) throws IOException {
// 读取字段
String sval = readField(tag);
// 转化
return Utils.fromCSVBuffer(sval);
} // 读取记录
public void readRecord(Record r, String tag) throws IOException {
// 反序列化
r.deserialize(this, tag);
} // 开始读取记录
public void startRecord(String tag) throws IOException {
if (tag != null && !"".equals(tag)) {
// 读取并转化为字符
char c1 = (char) stream.read();
// 读取并转化为字符
char c2 = (char) stream.read();
if (c1 != 's' || c2 != '{') { // 进行判断
throw new IOException("Error deserializing "+tag);
}
}
} // 结束读取记录
public void endRecord(String tag) throws IOException {
// 读取并转化为字符
char c = (char) stream.read();
if (tag == null || "".equals(tag)) {
if (c != '\n' && c != '\r') { // 进行判断
throw new IOException("Error deserializing record.");
} else {
return;
}
} if (c != '}') { // 进行判断
throw new IOException("Error deserializing "+tag);
}
// 读取并转化为字符
c = (char) stream.read();
if (c != ',') {
// 推回缓冲区
stream.unread(c);
} return;
} // 开始读取vector
public Index startVector(String tag) throws IOException {
char c1 = (char) stream.read();
char c2 = (char) stream.read();
if (c1 != 'v' || c2 != '{') {
throw new IOException("Error deserializing "+tag);
}
return new CsvIndex();
} // 结束读取vector
public void endVector(String tag) throws IOException {
char c = (char) stream.read();
if (c != '}') {
throw new IOException("Error deserializing "+tag);
}
c = (char) stream.read();
if (c != ',') {
stream.unread(c);
}
return;
} // 开始读取Map
public Index startMap(String tag) throws IOException {
char c1 = (char) stream.read();
char c2 = (char) stream.read();
if (c1 != 'm' || c2 != '{') {
throw new IOException("Error deserializing "+tag);
}
return new CsvIndex();
} // 结束读取Map
public void endMap(String tag) throws IOException {
char c = (char) stream.read();
if (c != '}') {
throw new IOException("Error deserializing "+tag);
}
c = (char) stream.read();
if (c != ',') {
stream.unread(c);
}
return;
}
}

  3. XmlInputArchive 

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.apache.jute; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
*
*/
class XmlInputArchive implements InputArchive {
// 内部类,值(包含类型和值)
static private class Value {
private String type;
private StringBuffer sb; public Value(String t) {
type = t;
sb = new StringBuffer();
} // 添加chars
public void addChars(char[] buf, int offset, int len) {
sb.append(buf, offset, len);
} // 返回value
public String getValue() { return sb.toString(); } // 返回type
public String getType() { return type; }
} // 内部类,XML解析器
private static class XMLParser extends DefaultHandler {
private boolean charsValid = false; private ArrayList<Value> valList; private XMLParser(ArrayList<Value> vlist) {
valList = vlist;
} // 文档开始,空的实现
public void startDocument() throws SAXException {} // 文档结束,空的实现
public void endDocument() throws SAXException {} // 开始解析元素
public void startElement(String ns,
String sname,
String qname,
Attributes attrs) throws SAXException {
//
charsValid = false;
if ("boolean".equals(qname) || // boolean类型
"i4".equals(qname) || // 四个字节
"int".equals(qname) || // int类型
"string".equals(qname) || // String类型
"double".equals(qname) || // double类型
"ex:i1".equals(qname) || // 一个字节
"ex:i8".equals(qname) || // 八个字节
"ex:float".equals(qname)) { // 基本类型
//
charsValid = true;
// 添加至列表
valList.add(new Value(qname));
} else if ("struct".equals(qname) ||
"array".equals(qname)) { // 结构体或数组类型
// 添加至列表
valList.add(new Value(qname));
}
} // 结束解析元素
public void endElement(String ns,
String sname,
String qname) throws SAXException {
charsValid = false;
if ("struct".equals(qname) ||
"array".equals(qname)) { // 结构体或数组类型
// 添加至列表
valList.add(new Value("/"+qname));
}
} public void characters(char buf[], int offset, int len)
throws SAXException {
if (charsValid) { // 是否合法
// 从列表获取value
Value v = valList.get(valList.size()-1);
// 将buf添加至value
v.addChars(buf, offset,len);
}
} } // 内部类,对应XmlInputArchive
private class XmlIndex implements Index {
// 是否已经完成
public boolean done() {
// 根据索引获取value
Value v = valList.get(vIdx);
if ("/array".equals(v.getType())) { // 类型为/array
// 设置开索引值为null
valList.set(vIdx, null);
// 增加索引值
vIdx++;
return true;
} else {
return false;
}
}
// 增加索引值,空的实现
public void incr() {}
} // 值列表
private ArrayList<Value> valList;
// 值长度
private int vLen;
// 索引
private int vIdx; // 下一项
private Value next() throws IOException {
if (vIdx < vLen) { // 当前索引值小于长度
// 获取值
Value v = valList.get(vIdx);
// 设置索引值为null
valList.set(vIdx, null);
// 增加索引值
vIdx++;
return v;
} else {
throw new IOException("Error in deserialization.");
}
} // 获取XmlInputArchive
static XmlInputArchive getArchive(InputStream strm)
throws ParserConfigurationException, SAXException, IOException {
return new XmlInputArchive(strm);
} /** Creates a new instance of BinaryInputArchive */
// 构造函数
public XmlInputArchive(InputStream in)
throws ParserConfigurationException, SAXException, IOException {
// 初始化XmlInputArchive的相应字段
valList = new ArrayList<Value>();
DefaultHandler handler = new XMLParser(valList);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
parser.parse(in, handler);
vLen = valList.size();
vIdx = 0;
} // 读取byte类型
public byte readByte(String tag) throws IOException {
Value v = next();
if (!"ex:i1".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return Byte.parseByte(v.getValue());
} // 读取Boolean类型
public boolean readBool(String tag) throws IOException {
Value v = next();
if (!"boolean".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return "1".equals(v.getValue());
} // 读取int类型
public int readInt(String tag) throws IOException {
Value v = next();
if (!"i4".equals(v.getType()) &&
!"int".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return Integer.parseInt(v.getValue());
} // 读取long类型
public long readLong(String tag) throws IOException {
Value v = next();
if (!"ex:i8".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return Long.parseLong(v.getValue());
} // 读取float类型
public float readFloat(String tag) throws IOException {
Value v = next();
if (!"ex:float".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return Float.parseFloat(v.getValue());
} // 读取double类型
public double readDouble(String tag) throws IOException {
Value v = next();
if (!"double".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return Double.parseDouble(v.getValue());
} // 读取String类型
public String readString(String tag) throws IOException {
Value v = next();
if (!"string".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return Utils.fromXMLString(v.getValue());
} // 读取Buffer类型
public byte[] readBuffer(String tag) throws IOException {
Value v = next();
if (!"string".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return Utils.fromXMLBuffer(v.getValue());
} // 读取Record类型
public void readRecord(Record r, String tag) throws IOException {
r.deserialize(this, tag);
} // 开始读取Record
public void startRecord(String tag) throws IOException {
Value v = next();
if (!"struct".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
} // 结束读取Record
public void endRecord(String tag) throws IOException {
Value v = next();
if (!"/struct".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
} // 开始读取vector
public Index startVector(String tag) throws IOException {
Value v = next();
if (!"array".equals(v.getType())) {
throw new IOException("Error deserializing "+tag+".");
}
return new XmlIndex();
} // 结束读取vector
public void endVector(String tag) throws IOException {} // 开始读取Map
public Index startMap(String tag) throws IOException {
return startVector(tag);
} // 停止读取Map
public void endMap(String tag) throws IOException { endVector(tag); } }

  2.2 OutputArchive

  其是所有序列化器都需要实现此接口,其方法如下。  

public interface OutputArchive {
// 写Byte类型
public void writeByte(byte b, String tag) throws IOException;
// 写boolean类型
public void writeBool(boolean b, String tag) throws IOException;
// 写int类型
public void writeInt(int i, String tag) throws IOException;
// 写long类型
public void writeLong(long l, String tag) throws IOException;
// 写float类型
public void writeFloat(float f, String tag) throws IOException;
// 写double类型
public void writeDouble(double d, String tag) throws IOException;
// 写String类型
public void writeString(String s, String tag) throws IOException;
// 写Buffer类型
public void writeBuffer(byte buf[], String tag)
throws IOException;
// 写Record类型
public void writeRecord(Record r, String tag) throws IOException;
// 开始写Record
public void startRecord(Record r, String tag) throws IOException;
// 结束写Record
public void endRecord(Record r, String tag) throws IOException;
// 开始写Vector
public void startVector(List v, String tag) throws IOException;
// 结束写Vector
public void endVector(List v, String tag) throws IOException;
// 开始写Map
public void startMap(TreeMap v, String tag) throws IOException;
// 结束写Map
public void endMap(TreeMap v, String tag) throws IOException; }

  OutputArchive的类结构如下

  

  1. BinaryOutputArchive 

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.apache.jute; import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.TreeMap; /**
*
*/
public class BinaryOutputArchive implements OutputArchive {
// 字节缓冲
private ByteBuffer bb = ByteBuffer.allocate(1024);
// DataInput接口,用于从二进制流中读取字节
private DataOutput out; // 静态方法,用于获取Archive
public static BinaryOutputArchive getArchive(OutputStream strm) {
return new BinaryOutputArchive(new DataOutputStream(strm));
} /** Creates a new instance of BinaryOutputArchive */
// 构造函数
public BinaryOutputArchive(DataOutput out) {
this.out = out;
} // 写Byte类型
public void writeByte(byte b, String tag) throws IOException {
out.writeByte(b);
} // 写boolean类型
public void writeBool(boolean b, String tag) throws IOException {
out.writeBoolean(b);
} // 写int类型
public void writeInt(int i, String tag) throws IOException {
out.writeInt(i);
} // 写long类型
public void writeLong(long l, String tag) throws IOException {
out.writeLong(l);
} // 写float类型
public void writeFloat(float f, String tag) throws IOException {
out.writeFloat(f);
} // 写double类型
public void writeDouble(double d, String tag) throws IOException {
out.writeDouble(d);
} /**
* create our own char encoder to utf8. This is faster
* then string.getbytes(UTF8).
* @param s the string to encode into utf8
* @return utf8 byte sequence.
*/
// 将String类型转化为ByteBuffer类型
final private ByteBuffer stringToByteBuffer(CharSequence s) {
// 清空ByteBuffer
bb.clear();
// s的长度
final int len = s.length();
for (int i = 0; i < len; i++) { // 遍历s
if (bb.remaining() < 3) { // ByteBuffer剩余大小小于3
// 再进行一次分配(扩大一倍)
ByteBuffer n = ByteBuffer.allocate(bb.capacity() << 1);
// 切换方式
bb.flip();
// 写入bb
n.put(bb);
bb = n;
}
char c = s.charAt(i);
if (c < 0x80) { // 小于128,直接写入
bb.put((byte) c);
} else if (c < 0x800) { // 小于2048,则进行相应处理
bb.put((byte) (0xc0 | (c >> 6)));
bb.put((byte) (0x80 | (c & 0x3f)));
} else { // 大于2048,则进行相应处理
bb.put((byte) (0xe0 | (c >> 12)));
bb.put((byte) (0x80 | ((c >> 6) & 0x3f)));
bb.put((byte) (0x80 | (c & 0x3f)));
}
}
// 切换方式
bb.flip();
return bb;
} // 写String类型
public void writeString(String s, String tag) throws IOException {
if (s == null) {
writeInt(-1, "len");
return;
}
ByteBuffer bb = stringToByteBuffer(s);
writeInt(bb.remaining(), "len");
out.write(bb.array(), bb.position(), bb.limit());
} // 写Buffer类型
public void writeBuffer(byte barr[], String tag)
throws IOException {
if (barr == null) {
out.writeInt(-1);
return;
}
out.writeInt(barr.length);
out.write(barr);
} // 写Record类型
public void writeRecord(Record r, String tag) throws IOException {
r.serialize(this, tag);
} // 开始写Record
public void startRecord(Record r, String tag) throws IOException {} // 结束写Record
public void endRecord(Record r, String tag) throws IOException {} // 开始写Vector
public void startVector(List v, String tag) throws IOException {
if (v == null) {
writeInt(-1, tag);
return;
}
writeInt(v.size(), tag);
} // 结束写Vector
public void endVector(List v, String tag) throws IOException {} // 开始写Map
public void startMap(TreeMap v, String tag) throws IOException {
writeInt(v.size(), tag);
} // 结束写Map
public void endMap(TreeMap v, String tag) throws IOException {} }

  2. CsvOutputArchive 

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.apache.jute; import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.TreeMap; /**
*
*/
public class CsvOutputArchive implements OutputArchive {
// PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式
private PrintStream stream;
// 默认为第一次
private boolean isFirst = true; // 获取Archive
static CsvOutputArchive getArchive(OutputStream strm)
throws UnsupportedEncodingException {
return new CsvOutputArchive(strm);
} // 私有函数,抛出异常
private void throwExceptionOnError(String tag) throws IOException {
if (stream.checkError()) {
throw new IOException("Error serializing "+tag);
}
} // 私有函数,除第一次外,均打印","
private void printCommaUnlessFirst() {
if (!isFirst) {
stream.print(",");
}
isFirst = false;
} /** Creates a new instance of CsvOutputArchive */
// 构造函数
public CsvOutputArchive(OutputStream out)
throws UnsupportedEncodingException {
stream = new PrintStream(out, true, "UTF-8");
} // 写Byte类型
public void writeByte(byte b, String tag) throws IOException {
writeLong((long)b, tag);
} // 写boolean类型
public void writeBool(boolean b, String tag) throws IOException {
// 打印","
printCommaUnlessFirst();
String val = b ? "T" : "F";
// 打印值
stream.print(val);
// 抛出异常
throwExceptionOnError(tag);
} // 写int类型
public void writeInt(int i, String tag) throws IOException {
writeLong((long)i, tag);
} // 写long类型
public void writeLong(long l, String tag) throws IOException {
printCommaUnlessFirst();
stream.print(l);
throwExceptionOnError(tag);
} // 写float类型
public void writeFloat(float f, String tag) throws IOException {
writeDouble((double)f, tag);
} // 写double类型
public void writeDouble(double d, String tag) throws IOException {
printCommaUnlessFirst();
stream.print(d);
throwExceptionOnError(tag);
} // 写String类型
public void writeString(String s, String tag) throws IOException {
printCommaUnlessFirst();
stream.print(Utils.toCSVString(s));
throwExceptionOnError(tag);
} // 写Buffer类型
public void writeBuffer(byte buf[], String tag)
throws IOException {
printCommaUnlessFirst();
stream.print(Utils.toCSVBuffer(buf));
throwExceptionOnError(tag);
} // 写Record类型
public void writeRecord(Record r, String tag) throws IOException {
if (r == null) {
return;
}
r.serialize(this, tag);
} // 开始写Record
public void startRecord(Record r, String tag) throws IOException {
if (tag != null && !"".equals(tag)) {
printCommaUnlessFirst();
stream.print("s{");
isFirst = true;
}
} // 结束写Record
public void endRecord(Record r, String tag) throws IOException {
if (tag == null || "".equals(tag)) {
stream.print("\n");
isFirst = true;
} else {
stream.print("}");
isFirst = false;
}
} // 开始写Vector
public void startVector(List v, String tag) throws IOException {
printCommaUnlessFirst();
stream.print("v{");
isFirst = true;
} // 结束写Vector
public void endVector(List v, String tag) throws IOException {
stream.print("}");
isFirst = false;
} // 开始写Map
public void startMap(TreeMap v, String tag) throws IOException {
printCommaUnlessFirst();
stream.print("m{");
isFirst = true;
} // 结束写Map
public void endMap(TreeMap v, String tag) throws IOException {
stream.print("}");
isFirst = false;
}
}

  3. XmlOutputArchive

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.apache.jute; import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Stack;
import java.util.TreeMap; /**
*
*/
class XmlOutputArchive implements OutputArchive {
// PrintStream为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式
private PrintStream stream; // 缩进个数
private int indent = 0; // 栈结构
private Stack<String> compoundStack; // 存放缩进
private void putIndent() {
StringBuilder sb = new StringBuilder("");
for (int idx = 0; idx < indent; idx++) {
sb.append(" ");
}
stream.print(sb.toString());
} // 添加缩进
private void addIndent() {
indent++;
} // 减少缩进
private void closeIndent() {
indent--;
} // 打印文件头格式
private void printBeginEnvelope(String tag) {
if (!compoundStack.empty()) {
String s = compoundStack.peek();
if ("struct".equals(s)) {
putIndent();
stream.print("<member>\n");
addIndent();
putIndent();
stream.print("<name>"+tag+"</name>\n");
putIndent();
stream.print("<value>");
} else if ("vector".equals(s)) {
stream.print("<value>");
} else if ("map".equals(s)) {
stream.print("<value>");
}
} else {
stream.print("<value>");
}
} // 打印文件尾格式
private void printEndEnvelope(String tag) {
if (!compoundStack.empty()) {
String s = compoundStack.peek();
if ("struct".equals(s)) {
stream.print("</value>\n");
closeIndent();
putIndent();
stream.print("</member>\n");
} else if ("vector".equals(s)) {
stream.print("</value>\n");
} else if ("map".equals(s)) {
stream.print("</value>\n");
}
} else {
stream.print("</value>\n");
}
} //
private void insideVector(String tag) {
printBeginEnvelope(tag);
compoundStack.push("vector");
} private void outsideVector(String tag) throws IOException {
String s = compoundStack.pop();
if (!"vector".equals(s)) {
throw new IOException("Error serializing vector.");
}
printEndEnvelope(tag);
} private void insideMap(String tag) {
printBeginEnvelope(tag);
compoundStack.push("map");
} private void outsideMap(String tag) throws IOException {
String s = compoundStack.pop();
if (!"map".equals(s)) {
throw new IOException("Error serializing map.");
}
printEndEnvelope(tag);
} private void insideRecord(String tag) {
printBeginEnvelope(tag);
compoundStack.push("struct");
} private void outsideRecord(String tag) throws IOException {
String s = compoundStack.pop();
if (!"struct".equals(s)) {
throw new IOException("Error serializing record.");
}
printEndEnvelope(tag);
} // 获取Archive
static XmlOutputArchive getArchive(OutputStream strm) {
return new XmlOutputArchive(strm);
} /** Creates a new instance of XmlOutputArchive */
// 构造函数
public XmlOutputArchive(OutputStream out) {
stream = new PrintStream(out);
compoundStack = new Stack<String>();
} // 写Byte类型
public void writeByte(byte b, String tag) throws IOException {
printBeginEnvelope(tag);
stream.print("<ex:i1>");
stream.print(Byte.toString(b));
stream.print("</ex:i1>");
printEndEnvelope(tag);
} // 写boolean类型
public void writeBool(boolean b, String tag) throws IOException {
printBeginEnvelope(tag);
stream.print("<boolean>");
stream.print(b ? "1" : "0");
stream.print("</boolean>");
printEndEnvelope(tag);
} // 写int类型
public void writeInt(int i, String tag) throws IOException {
printBeginEnvelope(tag);
stream.print("<i4>");
stream.print(Integer.toString(i));
stream.print("</i4>");
printEndEnvelope(tag);
} // 写long类型
public void writeLong(long l, String tag) throws IOException {
printBeginEnvelope(tag);
stream.print("<ex:i8>");
stream.print(Long.toString(l));
stream.print("</ex:i8>");
printEndEnvelope(tag);
} // 写float类型
public void writeFloat(float f, String tag) throws IOException {
printBeginEnvelope(tag);
stream.print("<ex:float>");
stream.print(Float.toString(f));
stream.print("</ex:float>");
printEndEnvelope(tag);
} // 写double类型
public void writeDouble(double d, String tag) throws IOException {
printBeginEnvelope(tag);
stream.print("<double>");
stream.print(Double.toString(d));
stream.print("</double>");
printEndEnvelope(tag);
} // 写String类型
public void writeString(String s, String tag) throws IOException {
printBeginEnvelope(tag);
stream.print("<string>");
stream.print(Utils.toXMLString(s));
stream.print("</string>");
printEndEnvelope(tag);
} // 写Buffer类型
public void writeBuffer(byte buf[], String tag)
throws IOException {
printBeginEnvelope(tag);
stream.print("<string>");
stream.print(Utils.toXMLBuffer(buf));
stream.print("</string>");
printEndEnvelope(tag);
} // 写Record类型
public void writeRecord(Record r, String tag) throws IOException {
r.serialize(this, tag);
} // 开始写Record类型
public void startRecord(Record r, String tag) throws IOException {
insideRecord(tag);
stream.print("<struct>\n");
addIndent();
} // 结束写Record类型
public void endRecord(Record r, String tag) throws IOException {
closeIndent();
putIndent();
stream.print("</struct>");
outsideRecord(tag);
} // 开始写Vector类型
public void startVector(List v, String tag) throws IOException {
insideVector(tag);
stream.print("<array>\n");
addIndent();
} // 结束写Vector类型
public void endVector(List v, String tag) throws IOException {
closeIndent();
putIndent();
stream.print("</array>");
outsideVector(tag);
} // 开始写Map类型
public void startMap(TreeMap v, String tag) throws IOException {
insideMap(tag);
stream.print("<array>\n");
addIndent();
} // 结束写Map类型
public void endMap(TreeMap v, String tag) throws IOException {
closeIndent();
putIndent();
stream.print("</array>");
outsideMap(tag);
} }

  2.3 Index

  其用于迭代反序列化器的迭代器。  

public interface Index {
// 是否已经完成
public boolean done();
// 下一项
public void incr();
}

  Index的类结构如下

  

  1. BinaryIndex 

    static private class BinaryIndex implements Index {
// 元素个数
private int nelems;
// 构造函数
BinaryIndex(int nelems) {
this.nelems = nelems;
}
// 是否已经完成
public boolean done() {
return (nelems <= 0);
}
// 移动一项
public void incr() {
nelems--;
}
}

  2. CsxIndex 

    private class CsvIndex implements Index {
// 是否已经完成
public boolean done() {
char c = '\0';
try {
// 读取字符
c = (char) stream.read();
// 推回缓冲区
stream.unread(c);
} catch (IOException ex) {
}
return (c == '}') ? true : false;
}
// 什么都不做
public void incr() {}
}

  3. XmlIndex 

    private class XmlIndex implements Index {
// 是否已经完成
public boolean done() {
// 根据索引获取值
Value v = valList.get(vIdx);
if ("/array".equals(v.getType())) { // 判断是否值的类型是否为/array
// 设置索引的值
valList.set(vIdx, null);
// 索引加1
vIdx++;
return true;
} else {
return false;
}
}
// 什么都不做
public void incr() {}
}

  2.4 Record

  所有用于网络传输或者本地存储的类型都实现该接口,其方法如下  

public interface Record {
// 序列化
public void serialize(OutputArchive archive, String tag)
throws IOException;
// 反序列化
public void deserialize(InputArchive archive, String tag)
throws IOException;
}

  所有的实现类都需要实现seriallize和deserialize方法。

三、示例

  下面通过一个示例来理解OutputArchive和InputArchive的搭配使用。 

package com.leesf.zookeeper_samples;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.TreeMap; import org.apache.jute.BinaryInputArchive;
import org.apache.jute.BinaryOutputArchive;
import org.apache.jute.Index;
import org.apache.jute.InputArchive;
import org.apache.jute.OutputArchive;
import org.apache.jute.Record; public class ArchiveTest {
public static void main( String[] args ) throws IOException {
String path = "F:\\test.txt";
// write operation
OutputStream outputStream = new FileOutputStream(new File(path));
BinaryOutputArchive binaryOutputArchive = BinaryOutputArchive.getArchive(outputStream); binaryOutputArchive.writeBool(true, "boolean");
byte[] bytes = "leesf".getBytes();
binaryOutputArchive.writeBuffer(bytes, "buffer");
binaryOutputArchive.writeDouble(13.14, "double");
binaryOutputArchive.writeFloat(5.20f, "float");
binaryOutputArchive.writeInt(520, "int");
Person person = new Person(25, "leesf");
binaryOutputArchive.writeRecord(person, "leesf");
TreeMap<String, Integer> map = new TreeMap<String, Integer>();
map.put("leesf", 25);
map.put("dyd", 25);
Set<String> keys = map.keySet();
binaryOutputArchive.startMap(map, "map");
int i = 0;
for (String key: keys) {
String tag = i + "";
binaryOutputArchive.writeString(key, tag);
binaryOutputArchive.writeInt(map.get(key), tag);
i++;
} binaryOutputArchive.endMap(map, "map"); // read operation
InputStream inputStream = new FileInputStream(new File(path));
BinaryInputArchive binaryInputArchive = BinaryInputArchive.getArchive(inputStream); System.out.println(binaryInputArchive.readBool("boolean"));
System.out.println(new String(binaryInputArchive.readBuffer("buffer")));
System.out.println(binaryInputArchive.readDouble("double"));
System.out.println(binaryInputArchive.readFloat("float"));
System.out.println(binaryInputArchive.readInt("int"));
Person person2 = new Person();
binaryInputArchive.readRecord(person2, "leesf");
System.out.println(person2); Index index = binaryInputArchive.startMap("map");
int j = 0;
while (!index.done()) {
String tag = j + "";
System.out.println("key = " + binaryInputArchive.readString(tag)
+ ", value = " + binaryInputArchive.readInt(tag));
index.incr();
j++;
}
} static class Person implements Record {
private int age;
private String name; public Person() { } public Person(int age, String name) {
this.age = age;
this.name = name;
} public void serialize(OutputArchive archive, String tag) throws IOException {
archive.startRecord(this, tag);
archive.writeInt(age, "age");
archive.writeString(name, "name");
archive.endRecord(this, tag);
} public void deserialize(InputArchive archive, String tag) throws IOException {
archive.startRecord(tag);
age = archive.readInt("age");
name = archive.readString("name");
archive.endRecord(tag);
} public String toString() {
return "age = " + age + ", name = " + name;
}
}
}

  运行结果:  

true
leesf
13.14
5.2
520
age = 25, name = leesf
key = dyd, value = 25
key = leesf, value = 25

四、总结

  本篇博文分析了序列化中涉及到的类,主要是org.zookeeper.jute包下的类,相对来说还是相对简单,也谢谢各位园友的观看~

【Zookeeper】源码分析之序列化的更多相关文章

  1. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  2. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  3. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  4. Zookeeper 源码分析-启动

    Zookeeper 源码分析-启动 博客分类: Zookeeper   本文主要介绍了zookeeper启动的过程 运行zkServer.sh start命令可以启动zookeeper.入口的main ...

  5. storm操作zookeeper源码分析-cluster.clj

    storm操作zookeeper的主要函数都定义在命名空间backtype.storm.cluster中(即cluster.clj文件中).backtype.storm.cluster定义了两个重要p ...

  6. Hadoop2源码分析-序列化篇

    1.概述 上一篇我们了解了MapReduce的相关流程,包含MapReduce V2的重构思路,新的设计架构,与MapReduce V1的区别等内容,今天我们在来学习下在Hadoop V2中的序列化的 ...

  7. zookeeper源码分析之leader选举

    zookeeper提供顺序一致性.原子性.统一视图.可靠性保证服务zookeeper使用的是zab(atomic broadcast protocol)协议而非paxos协议zookeeper能处理并 ...

  8. ZooKeeper源码分析:Quorum请求的整个流程(转)

    Quorum请求是转发给Leader处理,并且需要得一个Follower Quorum确认的请求.这些请求包括: 1)znode的写操作(OpCode.create,OpCode.delete,OpC ...

  9. zookeeper源码分析之二客户端启动

    ZooKeeper Client Library提供了丰富直观的API供用户程序使用,下面是一些常用的API: create(path, data, flags): 创建一个ZNode, path是其 ...

随机推荐

  1. 一分钟了解ArrayList和Vector的区别

    一.是否是线程安全的 Vector是同步的, 而ArrayList不是.因为Vector是同步的, 所以它是线程安全的.同样, 因为Vecotr是同步的, 所以他需要额外的开销来维持同步锁, 所以它要 ...

  2. [转]RSYNC 参数中文详解

    FROM : http://www.qiansw.com/rsync-cn.html rsync是一款好用的*nux文件同步工具.下面是其参数的中文解释. Rsync 参数选项说明 -v, --ver ...

  3. you have mixed tabs and spaces fix this

    http://blog.csdn.net/tonyyan19781/article/details/60882443 Vs2013 IDE下,编辑C++的工程源码,在打开文件的时候,会出现 " ...

  4. 【没有注意过的细节】用scanf读一个unsigned char? %hhu 的用法

    头段时间我的代码,有一个 unsigned char,我需要从sscanf 中读取字符串为这个值.但是一般char 是用%c的,我是要值得. 所以我使用了%d %u来读,结果报警告: unsigned ...

  5. Java SPI(Service Provider Interface)简介

    SPI 简介 SPI 全称为(Service Provider Interface),是JDK内置的一种服务提供发现机制. 一个服务(Service)通常指的是已知的接口或者抽象类,服务提供方就是对这 ...

  6. maven-shade-plugin 入门指南

    1. Why? 通过 maven-shade-plugin 生成一个 uber-jar,它包含所有的依赖 jar 包. 2. Goals Goal Description shade:help Dis ...

  7. tensorflow 之tf.nn.depthwise_conv2d and separable_conv2d实现及原理

    Depthwise Separable Convolution 1.简介 Depthwise Separable Convolution 是谷歌公司于2017年的CVPR中在论文”Xception: ...

  8. 成为Linux内核高手的四个方法

    首页 最新文章 资讯 程序员 设计 IT技术 创业 在国外 营销 趣文 特别分享 更多 > - Navigation -首页最新文章资讯程序员设计IT技术- Java & Android ...

  9. OpenGL® ES 3.0 Programming Guide - Book Website

    OpenGL® ES 3.0 Programming Guide - Book Website http://opengles-book.com sample codes in GitHub: htt ...

  10. Direct2D教程III——几何(Geometry)对象

    目前博客园中成系列的Direct2D的教程有 1.万一的 Direct2D 系列,用的是Delphi 2009 2.zdd的 Direct2D 系列,用的是VS中的C++ 3.本文所在的 Direct ...