43-微服务技术栈(高级):分布式协调服务zookeeper源码篇(序列化)

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 在完成了前面的理论学习后,现在可以从源码角度来解析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包下
  • 常用的类有:
  • InputArchive
  • OutputArchive
  • Index
  • Record
相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
6天前
|
Java API 微服务
【Spring Boot系列】通过OpenAPI规范构建微服务服务接口
【4月更文挑战第5天】通过OpenAPI接口构建Spring Boot服务RestAPI接口
|
13天前
|
监控 负载均衡 Cloud Native
ZooKeeper分布式协调服务详解:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析ZooKeeper分布式协调服务原理,涵盖核心概念如Server、Client、ZNode、ACL、Watcher,以及ZAB协议在一致性、会话管理、Leader选举中的作用。讨论ZooKeeper数据模型、操作、会话管理、集群部署与管理、性能调优和监控。同时,文章探讨了ZooKeeper在分布式锁、队列、服务注册与发现等场景的应用,并在面试方面分析了与其它服务的区别、实战挑战及解决方案。附带Java客户端实现分布式锁的代码示例,助力提升面试表现。
30 2
|
1月前
|
SpringCloudAlibaba Java 网络架构
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(七)Spring Cloud Gateway服务网关
98 0
|
13天前
|
监控 Sentinel 微服务
微服务的防御之道:服务雪崩、服务熔断、服务降级
微服务的防御之道:服务雪崩、服务熔断、服务降级
20 1
|
15天前
|
监控 数据可视化 安全
智慧工地SaaS可视化平台源码,PC端+APP端,支持二开,项目使用,微服务+Java++vue+mysql
环境实时数据、动态监测报警,实时监控施工环境状态,有针对性地预防施工过程中的环境污染问题,打造文明生态施工,创造绿色的生态环境。
13 0
智慧工地SaaS可视化平台源码,PC端+APP端,支持二开,项目使用,微服务+Java++vue+mysql
|
26天前
|
Java fastjson 数据安全/隐私保护
【Dubbo3技术专题】「云原生微服务开发实战」 一同探索和分析研究RPC服务的底层原理和实现
【Dubbo3技术专题】「云原生微服务开发实战」 一同探索和分析研究RPC服务的底层原理和实现
39 0
|
1月前
|
消息中间件 SpringCloudAlibaba Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(八)Config服务配置+bus消息总线+stream消息驱动+Sleuth链路追踪
783 0
|
1月前
|
SpringCloudAlibaba 负载均衡 Java
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(三)Eureka服务注册中心
【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(三)Eureka服务注册中心
44 1
|
1月前
|
NoSQL 算法 安全
Redlock 算法-主从redis分布式锁主节点宕机锁丢失的问题
Redlock 算法-主从redis分布式锁主节点宕机锁丢失的问题
154 0
|
1月前
|
NoSQL 关系型数据库 MySQL
分布式锁(redis/mysql)
分布式锁(redis/mysql)
58 1

相关产品

  • 微服务引擎