一、前言

  在完成了前面的理论学习后,现在可以从源码角度来解析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 源码(二)序列化组件 Jute

    Zookeeper 源码(二)序列化组件 Jute 一.序列化组件 Jute 对于一个网络通信,首先需要解决的就是对数据的序列化和反序列化处理,在 ZooKeeper 中,使用了Jute 这一序列化组 ...

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

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

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

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

  4. Zookeeper源码(启动+选举)

    简介 关于Zookeeper,目前普遍的应用场景基本作为服务注册中心,用于服务发现.但这只是Zookeeper的一个的功能,根据Apache的官方概述:"The Apache ZooKeep ...

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

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

  6. 如何编译Zookeeper源码

    1. 安装Ant Ant下载地址:http://ant.apache.org/bindownload.cgi 解压即可. 2. 下载Zookeeper源码包 https://github.com/ap ...

  7. Zookeeper源码编译为Eclipse工程(转)

    原文地址:http://blog.csdn.net/jiyiqinlovexx/article/details/41179293 为了深入学习ZooKeeper源码,首先就想到将其导入到Eclispe ...

  8. Zookeeper 源码分析-启动

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

  9. 使用ant编译zookeeper源码

    1. 安装Ant Ant下载地址:http://ant.apache.org/bindownload.cgi 解压即可. 注意如果不配置环境变量的话需要使用绝对路径,我配置了. 开始我ant跑错了 U ...

  10. Zookeeper源码编译为Eclipse工程(win7下Ant编译)

    前言 ZooKeeper是雅虎的.用Ant进行软件构建. 千里之行,始于足下.想看源码的第一步,是下载源码并导入某个IDE工具. Ant http://ant.apache.org/ Windows: ...

随机推荐

  1. 用javascript把扑克牌理理顺!

    打扑克的人都知道,比如斗地主! 我们一般都会按照顺序把随机摸过来的牌从小到大的顺序在手上理整齐(记得小时候打牌两副牌手都抓不过来),这篇随笔就是想通过实现这个功能来熟悉下js中排序数组等相关知识. 用 ...

  2. SQL点滴21—几个有点偏的语句

    原文:SQL点滴21-几个有点偏的语句 SQL语句是一种集合操作,就是批量操作,它的速度要比其他的语言快,所以在设计的时候很多的逻辑都会放在sql语句或者存储过程中来实现,这个是一种设计思想.但是今天 ...

  3. C#使用COM搜索本地word文档关键字

    /// <summary> /// 检索根目录下的子目录及其所有文件,并在datagridview中显示文档名称及路径--递归调用 /// </summary> /// < ...

  4. 探秘IntelliJ IDEA 13测试版新功能——调试器显示本地变量

    IntelliJ IDEA在业界被公认为最好的Java开发平台之一,JetBrains公司将在12月正式发布IntelliJ IDEA 13版本. 现在,小编将和大家一起探秘密IntelliJ IDE ...

  5. SSIS Package to Call Web Service

    原文 SSIS Package to Call Web Service SSIS Package to Call Web Service. You can Call WebService from S ...

  6. redmine的邮件配置

    redmine的邮件配置 2012-01-04 18:09:21|  分类: 默认分类|举报|字号 订阅     redmine里要用到邮件通知,本来以为很是简单,网上也有许多教程,谁知忙活了一下午, ...

  7. sql 进制转换,支持93内的进制相互转换

    功能:实现在SQL内进制的互相转换,支持从2 - 93进制内的转换,若需要支持其他字符,可以自定义@ym变量实现扩充 -- ====================================== ...

  8. DDD 应对具体业务场景,Domain Model 重新设计

    DDD 应对具体业务场景,Domain Model 重新设计 写在前面 上联:no zuo no die why you try 下联:no try no high give me five 横批: ...

  9. Routing(路由) & Multiple Views(多个视图) step 7

    Routing(路由) & Multiple Views(多个视图) step 7 1.切换分支到step7,并启动项目 git checkout step-7 npm start 2.需求: ...

  10. Bootstrap 图像

    一般的样式 在我们讨论 Bootstrap 3 提供的定义图像样式的特殊的 class 之前,我们将看到 Bootstrap 3 提供的定义图像的一般的样式. img { border: 0; } 这 ...