【Zookeeper】源码分析之序列化
一、前言
在完成了前面的理论学习后,现在可以从源码角度来解析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包下的类,相对来说还是相对简单,也谢谢各位园友的观看~
PS:如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”,将会是我不竭的动力!
作者:leesf 掌控之中,才会成功;掌控之外,注定失败。
出处:http://www.cnblogs.com/leesf456/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果觉得本文对您有帮助,您可以请我喝杯咖啡!