zookeeper源碼分析--序列化篇

其實很多時候我們都在使用zkclient這款jar包對zk進行相關的操作,但是在zkclient裏面到底發生了什麼,我們卻並不是很清楚。對zk的瞭解出了簡單的節點創建,刪除,監聽以外,我們還可以加深對它的思想理解。
下邊我們來深入探討一下zk的內部機制:
其實我們清楚一點,zk是採用了java語言進行編寫的,因此關於zk這部分的內容對於java程序員來說是比較好接受的。
現在讓我們來看下zk裏面序列化部分:
在這裏插入圖片描述
在jute裏面有一個叫做record的接口,專門用於定義序列化和反序列化操作:

package org.apache.jute;
import java.io.IOException;
/**
 * Interface that is implemented by generated classes.
 * 
 */
public interface Record {
    public void serialize(OutputArchive archive, String tag)
        throws IOException;
    public void deserialize(InputArchive archive, String tag)
        throws IOException;
}

zk內部的jute是自己研發的一款用於處理序列化和反序列化操作的工具。核心的序列化和反序列化器有以下幾種:
BinaryInputArchive 處理二進制數據
BinaryOutputArchive

CsvInputArchive 處理csv格式數據
CsvOutputArchive

XmlInputArchive處理xml格式數據
XmlOutputArchive

下邊我們結合一段代碼案例來深入瞭解jute的序列化器工作使用方式:

package 源碼分析.jute包;
import lombok.Data;
import org.apache.jute.InputArchive;
import org.apache.jute.OutputArchive;
import org.apache.jute.Record;
import java.io.IOException;
/**
 * @author idea
 * @data 2019/10/27
 */
@Data
public class TestBean implements Record {
    private int number;
    private String name;
    public TestBean(int number, String name) {
        this.number = number;
        this.name = name;
    }
    public TestBean(){}
    @Override
    public void serialize(OutputArchive archive, String tag) throws IOException {
        System.out.println("tag output:"+tag);
        archive.startRecord(this,tag);
        archive.writeInt(this.number,"number");
        archive.writeString(this.name,"name");
        archive.endRecord(this,tag);
    }
    @Override
    public void deserialize(InputArchive archive, String tag) throws IOException {
        System.out.println("tag:"+tag);
        archive.startRecord(tag);
        this.number=archive.readInt("number");
        this.name=archive.readString("name");
        archive.endRecord(tag);
    }
}


接下來是我們的測試類

package 源碼分析.jute包;
import org.apache.jute.BinaryInputArchive;
import org.apache.jute.BinaryOutputArchive;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
 * @author idea
 * @data 2019/10/27
 */
public class TestDemo {
    public static void main(String[] args) throws IOException {
        //先序列化操作
        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        BinaryOutputArchive boa= BinaryOutputArchive.getArchive(baos);
        new TestBean(1,"idea").serialize(boa,"tag1");
        byte[] array=baos.toByteArray();
        ByteArrayInputStream bins=new ByteArrayInputStream(array);
        BinaryInputArchive bia=BinaryInputArchive.getArchive(bins);
        TestBean testBean=new TestBean();
        testBean.deserialize(bia,"tag1");
        System.out.println("int="+testBean.getNumber()+"--string="+testBean.getName());
        bins.close();
        baos.close();
    }
}

處理完畢之後,便是我們的數據展示環節了。
看完之後你可能會覺得,怎麼zk裏面的數據類型進行序列化和反序列化需要提前對bean做如此複雜的操作啊?是的,在zk源碼的
包org.apache.zookeeper.data下邊,會看到相應的類都做了非常複雜的操作,舉個案例來說,例如說Stat這個對象,在它的源碼裏面可以看到這樣的內容描述:

// File generated by hadoop record compiler. Do not edit.
package org.apache.zookeeper.data;
import org.apache.jute.*;
public class Stat implements Record {
  private long czxid;
  private long mzxid;
  private long ctime;
  private long mtime;
  private int version;
  private int cversion;
  private int aversion;
  private long ephemeralOwner;
  private int dataLength;
  private int numChildren;
  private long pzxid;
  public Stat() {
  }
  public Stat(
        long czxid,
        long mzxid,
        long ctime,
        long mtime,
        int version,
        int cversion,
        int aversion,
        long ephemeralOwner,
        int dataLength,
        int numChildren,
        long pzxid) {
    this.czxid=czxid;
    this.mzxid=mzxid;
    this.ctime=ctime;
    this.mtime=mtime;
    this.version=version;
    this.cversion=cversion;
    this.aversion=aversion;
    this.ephemeralOwner=ephemeralOwner;
    this.dataLength=dataLength;
    this.numChildren=numChildren;
    this.pzxid=pzxid;
  }
  public long getCzxid() {
    return czxid;
  }
  public void setCzxid(long m_) {
    czxid=m_;
  }
  public long getMzxid() {
    return mzxid;
  }
  public void setMzxid(long m_) {
    mzxid=m_;
  }
  public long getCtime() {
    return ctime;
  }
  public void setCtime(long m_) {
    ctime=m_;
  }
  public long getMtime() {
    return mtime;
  }
  public void setMtime(long m_) {
    mtime=m_;
  }
  public int getVersion() {
    return version;
  }
  public void setVersion(int m_) {
    version=m_;
  }
  public int getCversion() {
    return cversion;
  }
  public void setCversion(int m_) {
    cversion=m_;
  }
  public int getAversion() {
    return aversion;
  }
  public void setAversion(int m_) {
    aversion=m_;
  }
  public long getEphemeralOwner() {
    return ephemeralOwner;
  }
  public void setEphemeralOwner(long m_) {
    ephemeralOwner=m_;
  }
  public int getDataLength() {
    return dataLength;
  }
  public void setDataLength(int m_) {
    dataLength=m_;
  }
  public int getNumChildren() {
    return numChildren;
  }
  public void setNumChildren(int m_) {
    numChildren=m_;
  }
  public long getPzxid() {
    return pzxid;
  }
  public void setPzxid(long m_) {
    pzxid=m_;
  }
  public void serialize(OutputArchive a_, String tag) throws java.io.IOException {
    a_.startRecord(this,tag);
    a_.writeLong(czxid,"czxid");
    a_.writeLong(mzxid,"mzxid");
    a_.writeLong(ctime,"ctime");
    a_.writeLong(mtime,"mtime");
    a_.writeInt(version,"version");
    a_.writeInt(cversion,"cversion");
    a_.writeInt(aversion,"aversion");
    a_.writeLong(ephemeralOwner,"ephemeralOwner");
    a_.writeInt(dataLength,"dataLength");
    a_.writeInt(numChildren,"numChildren");
    a_.writeLong(pzxid,"pzxid");
    a_.endRecord(this,tag);
  }
  public void deserialize(InputArchive a_, String tag) throws java.io.IOException {
    a_.startRecord(tag);
    czxid=a_.readLong("czxid");
    mzxid=a_.readLong("mzxid");
    ctime=a_.readLong("ctime");
    mtime=a_.readLong("mtime");
    version=a_.readInt("version");
    cversion=a_.readInt("cversion");
    aversion=a_.readInt("aversion");
    ephemeralOwner=a_.readLong("ephemeralOwner");
    dataLength=a_.readInt("dataLength");
    numChildren=a_.readInt("numChildren");
    pzxid=a_.readLong("pzxid");
    a_.endRecord(tag);
}
  public String toString() {
    try {
      java.io.ByteArrayOutputStream s =
        new java.io.ByteArrayOutputStream();
      CsvOutputArchive a_ = 
        new CsvOutputArchive(s);
      a_.startRecord(this,"");
    a_.writeLong(czxid,"czxid");
    a_.writeLong(mzxid,"mzxid");
    a_.writeLong(ctime,"ctime");
    a_.writeLong(mtime,"mtime");
    a_.writeInt(version,"version");
    a_.writeInt(cversion,"cversion");
    a_.writeInt(aversion,"aversion");
    a_.writeLong(ephemeralOwner,"ephemeralOwner");
    a_.writeInt(dataLength,"dataLength");
    a_.writeInt(numChildren,"numChildren");
    a_.writeLong(pzxid,"pzxid");
      a_.endRecord(this,"");
      return new String(s.toByteArray(), "UTF-8");
    } catch (Throwable ex) {
      ex.printStackTrace();
    }
    return "ERROR";
  }
  public void write(java.io.DataOutput out) throws java.io.IOException {
    BinaryOutputArchive archive = new BinaryOutputArchive(out);
    serialize(archive, "");
  }
  public void readFields(java.io.DataInput in) throws java.io.IOException {
    BinaryInputArchive archive = new BinaryInputArchive(in);
    deserialize(archive, "");
  }
  public int compareTo (Object peer_) throws ClassCastException {
    if (!(peer_ instanceof Stat)) {
      throw new ClassCastException("Comparing different types of records.");
    }
    Stat peer = (Stat) peer_;
    int ret = 0;
    ret = (czxid == peer.czxid)? 0 :((czxid<peer.czxid)?-1:1);
    if (ret != 0) return ret;
    ret = (mzxid == peer.mzxid)? 0 :((mzxid<peer.mzxid)?-1:1);
    if (ret != 0) return ret;
    ret = (ctime == peer.ctime)? 0 :((ctime<peer.ctime)?-1:1);
    if (ret != 0) return ret;
    ret = (mtime == peer.mtime)? 0 :((mtime<peer.mtime)?-1:1);
    if (ret != 0) return ret;
    ret = (version == peer.version)? 0 :((version<peer.version)?-1:1);
    if (ret != 0) return ret;
    ret = (cversion == peer.cversion)? 0 :((cversion<peer.cversion)?-1:1);
    if (ret != 0) return ret;
    ret = (aversion == peer.aversion)? 0 :((aversion<peer.aversion)?-1:1);
    if (ret != 0) return ret;
    ret = (ephemeralOwner == peer.ephemeralOwner)? 0 :((ephemeralOwner<peer.ephemeralOwner)?-1:1);
    if (ret != 0) return ret;
    ret = (dataLength == peer.dataLength)? 0 :((dataLength<peer.dataLength)?-1:1);
    if (ret != 0) return ret;
    ret = (numChildren == peer.numChildren)? 0 :((numChildren<peer.numChildren)?-1:1);
    if (ret != 0) return ret;
    ret = (pzxid == peer.pzxid)? 0 :((pzxid<peer.pzxid)?-1:1);
    if (ret != 0) return ret;
     return ret;
  }
  public boolean equals(Object peer_) {
    if (!(peer_ instanceof Stat)) {
      return false;
    }
    if (peer_ == this) {
      return true;
    }
    Stat peer = (Stat) peer_;
    boolean ret = false;
    ret = (czxid==peer.czxid);
    if (!ret) return ret;
    ret = (mzxid==peer.mzxid);
    if (!ret) return ret;
    ret = (ctime==peer.ctime);
    if (!ret) return ret;
    ret = (mtime==peer.mtime);
    if (!ret) return ret;
    ret = (version==peer.version);
    if (!ret) return ret;
    ret = (cversion==peer.cversion);
    if (!ret) return ret;
    ret = (aversion==peer.aversion);
    if (!ret) return ret;
    ret = (ephemeralOwner==peer.ephemeralOwner);
    if (!ret) return ret;
    ret = (dataLength==peer.dataLength);
    if (!ret) return ret;
    ret = (numChildren==peer.numChildren);
    if (!ret) return ret;
    ret = (pzxid==peer.pzxid);
    if (!ret) return ret;
     return ret;
  }
  public int hashCode() {
    int result = 17;
    int ret;
    ret = (int) (czxid^(czxid>>>32));
    result = 37*result + ret;
    ret = (int) (mzxid^(mzxid>>>32));
    result = 37*result + ret;
    ret = (int) (ctime^(ctime>>>32));
    result = 37*result + ret;
    ret = (int) (mtime^(mtime>>>32));
    result = 37*result + ret;
    ret = (int)version;
    result = 37*result + ret;
    ret = (int)cversion;
    result = 37*result + ret;
    ret = (int)aversion;
    result = 37*result + ret;
    ret = (int) (ephemeralOwner^(ephemeralOwner>>>32));
    result = 37*result + ret;
    ret = (int)dataLength;
    result = 37*result + ret;
    ret = (int)numChildren;
    result = 37*result + ret;
    ret = (int) (pzxid^(pzxid>>>32));
    result = 37*result + ret;
    return result;
  }
  public static String signature() {
    return "LStat(lllliiiliil)";
  }
}

這段代碼非常的長,通過一些晚上的性能比對測試,會發現在速度方便jute的序列化性能要比protobuf好一些,但是碼流方面後者更佳。
本文講解了關於zk內部的序列化機制,認真觀看之後會發現,zk並沒有對jdk本身的序列化方式做什麼優化的手段,因此並沒有什麼過多的特別之處。更多的就是在DataInputStream那個位置加入了一些數據的接受和處理。

讓我們回顧一下以前寫過的一篇序列化文章,或許兩篇文章對比之後你會有不同的收穫和體會。
https://blog.csdn.net/Danny_idea/article/details/99620144

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章