自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Hessian 序列化、反序列化

原創(chuàng) 精選
運(yùn)維
序列化參數(shù)有枚舉屬性,序列化端增加一個(gè)枚舉,能否正常反序列化?序列化子類,它和父類有同名參數(shù),反序列化時(shí),同名參數(shù)能否能正常賦值?

背景

問題和思考:

  • 序列化參數(shù)有枚舉屬性,序列化端增加一個(gè)枚舉,能否正常反序列化?
  • 序列化子類,它和父類有同名參數(shù),反序列化時(shí),同名參數(shù)能否能正常賦值?
  • 序列化對(duì)象增加參數(shù),反序列化類不增加參數(shù),能否正常反序列化?
  • 用于序列化傳輸?shù)膶傩?,用包裝器比較好,還是基本類型比較好?

為什么要使用序列化和反序列化

  1. 程序在運(yùn)行過程中,產(chǎn)生的數(shù)據(jù),不能一直保存在內(nèi)存中,需要暫時(shí)或永久存儲(chǔ)到介質(zhì)(如磁盤、數(shù)據(jù)庫、文件)里進(jìn)行保存,也可能通過網(wǎng)絡(luò)發(fā)送給協(xié)作者。程序獲取原數(shù)據(jù),需要從介質(zhì),或網(wǎng)絡(luò)傳輸獲得。傳輸?shù)倪^程中,只能使用二進(jìn)制流進(jìn)行傳輸。
  2. 簡單的場(chǎng)景,基本類型數(shù)據(jù)傳輸。通過雙方約定好參數(shù)類型,數(shù)據(jù)接收方按照既定規(guī)則對(duì)二進(jìn)制流進(jìn)行反序列化。

圖片

  1. 復(fù)雜的場(chǎng)景,傳輸數(shù)據(jù)的參數(shù)類型可能包括:基本類型、包裝器類型、自定義類、枚舉、時(shí)間類型、字符串、容器等。很難簡單通過約定來反序列化二進(jìn)制流。需要一個(gè)通用的協(xié)議,共雙方使用,進(jìn)行序列化和反序列化。

三種序列化協(xié)議及對(duì)比

序列化協(xié)議

特點(diǎn)

jdk
(jdk 自帶)

1. 序列化:除了 static、transient類型
2. 特點(diǎn):強(qiáng)類型,安全性高,序列化結(jié)果攜帶類型信息
3. 反序列化:基于 Field 機(jī)制
4. 應(yīng)用場(chǎng)景:深拷貝

fastjson
(第三方實(shí)現(xiàn))

1. 可讀性好,空間占用小
2. 特點(diǎn):弱類型,序列化結(jié)果不攜帶類型信息,可讀性強(qiáng)。有一些安全性問題
3. 反序列化:基于 Field 機(jī)制,兼容 Bean 機(jī)制
4. 應(yīng)用場(chǎng)景:消息、透?jìng)鲗?duì)象

hessian
(第三方實(shí)現(xiàn))

1. 序列化:除了 static、transient 類型
2. 特點(diǎn):強(qiáng)類型,體積小,可跨語言,序列化結(jié)果攜帶類型信息
3. 反序列化:基于 Field 機(jī)制,兼容 Bean 機(jī)制
4. 應(yīng)用場(chǎng)景:RPC

對(duì)比

Father father = new Father();
father.name = "廚師";
father.comment = "川菜館";
father.simpleInt = 1;
father.boxInt = new Integer(10);
father.simpleDouble = 1;
father.boxDouble = new Double(10);
father.bigDecimal = new BigDecimal(11.5);

運(yùn)行結(jié)果:

jdk序列化結(jié)果長度:626,耗時(shí):55
jdk反序列化結(jié)果:Father{version=0, name='廚師', comment='川菜館', boxInt=10, simpleInt=1, boxDouble=10.0, simpleDouble=1.0, bigDecimal=11.5}耗時(shí):87

hessian序列化結(jié)果長度:182,耗時(shí):56
hessian反序列化結(jié)果:Father{version=0, name='廚師', comment='川菜館', boxInt=10, simpleInt=1, boxDouble=10.0, simpleDouble=1.0, bigDecimal=11.5}耗時(shí):7

Fastjson序列化結(jié)果長度:119,耗時(shí):225
Fastjson反序列化結(jié)果:Father{version=0, name='廚師', comment='川菜館', boxInt=10, simpleInt=1, boxDouble=10.0, simpleDouble=1.0, bigDecimal=11.5}耗時(shí):69

分析:

  • jdk 序列化耗時(shí)最短,但是序列化結(jié)果長度最長,是其它兩種的 3 ~ 5 倍。
  • fastjson 序列化結(jié)果長度最短,但是耗時(shí)是其它兩種的 4 倍左右。
  • hessian 序列化耗時(shí)與 jdk 差別不大,遠(yuǎn)小于 fastjson 序列化耗時(shí)。且與 jdk 相比,序列化結(jié)果占用空間非常有優(yōu)勢(shì)。另外,hessian 的反序列化速度最快,耗時(shí)是其它兩種的 1/10。
  • 綜上比較,hessian 在序列化和反序列化表現(xiàn)中,性能最優(yōu)。

Hessian 序列化實(shí)戰(zhàn)

實(shí)驗(yàn)準(zhǔn)備

父類

public class Father implements Serializable {

/**
* 靜態(tài)類型不會(huì)被序列化
*/
private static final long serialVersionUID = 1L;

/**
* transient 不會(huì)被序列化
*/
transient int version = 0;

/**
* 名稱
*/
public String name;

/**
* 備注
*/
public String comment;

/**
* 包裝器類型1
*/
public Integer boxInt;

/**
* 基本類型1
*/
public int simpleInt;

/**
* 包裝器類型2
*/
public Double boxDouble;

/**
* 基本類型2
*/
public double simpleDouble;

/**
* BigDecimal
*/
public BigDecimal bigDecimal;

public Father() {
}

@Override
public String toString() {
return "Father{" +
"version=" + version +
", name='" + name + '\'' +
", comment='" + comment + '\'' +
", boxInt=" + boxInt +
", simpleInt=" + simpleInt +
", boxDouble=" + boxDouble +
", simpleDouble=" + simpleDouble +
", bigDecimal=" + bigDecimal +
'}';
}
}

子類

public class Son extends Father {

/**
* 名稱,與father同名屬性
*/
public String name;

/**
* 自定義類
*/
public Attributes attributes;

/**
* 枚舉
*/
public Color color;

public Son() {
}

}

屬性-自定義類

public class Attributes implements Serializable {

private static final long serialVersionUID = 1L;

public int value;

public String msg;

public Attributes() {
}

public Attributes(int value, String msg) {
this.value = value;
this.msg = msg;
}

}

枚舉

public enum Color {

RED(1, "red"),
YELLOW(2, "yellow")
;

public int value;

public String msg;

Color() {
}

Color(int value, String msg) {
this.value = value;
this.msg = msg;
}
}

使用到的對(duì)象及屬性設(shè)置

Son son = new Son();
son.name = "廚師"; // 父子類同名字段,只給子類屬性賦值
son.comment = "川菜館";
son.simpleInt = 1;
son.boxInt = new Integer(10);
son.simpleDouble = 1;
son.boxDouble = new Double(10);
son.bigDecimal = new BigDecimal(11.5);
son.color = Color.RED;
son.attributes = new Attributes(11, "hello");

運(yùn)行結(jié)果分析

使用 Hessian 序列化,結(jié)果寫入文件,使用 vim 打開。使用 16 進(jìn)制方式查看,查看命令:%!xxd

00000000: 4307 6474 6f2e 536f 6e9a 046e 616d 6504  C.dto.Son..name.
00000010: 6e61 6d65 0763 6f6d 6d65 6e74 0662 6f78 name.comment.box
00000020: 496e 7409 7369 6d70 6c65 496e 7409 626f Int.simpleInt.bo
00000030: 7844 6f75 626c 650c 7369 6d70 6c65 446f xDouble.simpleDo
00000040: 7562 6c65 0a61 7474 7269 6275 7465 7305 uble.attributes.
00000050: 636f 6c6f 720a 6269 6744 6563 696d 616c color.bigDecimal
00000060: 6002 e58e a8e5 b888 4e03 e5b7 9de8 8f9c `.......N.......
00000070: e9a6 869a 915d 0a5c 430e 6474 6f2e 4174 .....].\C.dto.At
00000080: 7472 6962 7574 6573 9205 7661 6c75 6503 tributes..value.
00000090: 6d73 6761 9b05 6865 6c6c 6f43 0964 746f msga..helloC.dto
000000a0: 2e43 6f6c 6f72 9104 6e61 6d65 6203 5245 .Color..nameb.RE
000000b0: 4443 146a 6176 612e 6d61 7468 2e42 6967 DC.java.math.Big
000000c0: 4465 6369 6d61 6c91 0576 616c 7565 6304 Decimal..valuec.
000000d0: 3131 2e35 0a 11.5.

對(duì)其中的十六進(jìn)制數(shù)逐個(gè)分析,可以拆解為一下結(jié)構(gòu):參考 hessian 官方文檔,鏈接:http://hessian.caucho.com/doc/hessian-serialization.html

序列化原理

圖片

序列化規(guī)則:

  1. 被序列化的類必須實(shí)現(xiàn)了 Serializable 接口

圖片

  1. 靜態(tài)屬性和 transient 變量,不會(huì)被序列化。

圖片

  1. 枚舉類型在序列化后,存儲(chǔ)的是枚舉變量的名字
  2. 序列化結(jié)果的結(jié)構(gòu):類定義開始標(biāo)識(shí) C -> 類名長度+類名 -> 屬性數(shù)量 -> (逐個(gè))屬性名長度+屬性名 -> 開始實(shí)例化標(biāo)識(shí) -> (按照屬性名順序,逐個(gè)設(shè)置)屬性值(發(fā)現(xiàn)某個(gè)屬性是一個(gè)對(duì)象,循環(huán)這個(gè)過程)

圖片

反序列化

圖片

通俗原理圖:

圖片

圖片

解釋:這是前邊的序列化文件,可以對(duì)著這個(gè)結(jié)構(gòu)理解反序列化的過程。

圖片

解釋:讀取到“C”之后,它就知道接下來是一個(gè)類的定義,接著就開始讀取類名,屬性個(gè)數(shù)和每個(gè)屬性的名稱。并把這個(gè)類的定義緩存到一個(gè)_classDefs 的 list 里。

圖片

解釋:通過讀取序列化文件,獲得類名后,會(huì)加載這個(gè)類,并生成這個(gè)類的反序列化器。這里會(huì)生成一個(gè)_fieldMap,key 為反序列化端這個(gè)類所有屬性的名稱,value 為屬性對(duì)應(yīng)的反序列化器。

圖片

解釋:讀到 6 打頭的 2 位十六進(jìn)制數(shù)時(shí),開始類的實(shí)例化和賦值。

遺留問題解答:

  • 增加枚舉類型,反序列化不能正常讀取。

圖片

  • 原因:枚舉類型序列化結(jié)果中,枚舉屬性對(duì)應(yīng)的值是枚舉名。反序列化時(shí),通過枚舉類類名+枚舉名反射生成枚舉對(duì)象。枚舉名找不到就會(huì)報(bào)錯(cuò)。
  • 反序列化為子類型,同名屬性值無法正常賦值。

圖片

圖片

圖片

  • 序列化對(duì)象增加參數(shù),反序列化可以正常運(yùn)行。

圖片

原因:反序列化時(shí),是先通過類名加載同名類,并生成同名類的反序列化器,同名類每個(gè)屬性對(duì)應(yīng)的反序列化器存儲(chǔ)在一個(gè) map 中。在反序列化二進(jìn)制文件時(shí),通過讀取到的屬性名,到 map 中獲取對(duì)應(yīng)的反序列化器。若獲取不到,默認(rèn)是 NullFieldDeserializer.DESER。待到讀值的時(shí)候,僅讀值,不作 set 操作

  • 序列化和反序列化雙方都使用對(duì)象類型時(shí),更改屬性類型,若序列化方不傳輸數(shù)據(jù),序列化結(jié)果是‘N’,能正常反序列化。但是對(duì)于一方是基本類型,更改屬性類型后,因?yàn)?hessian 對(duì)于基本類型使用不同范圍的值域,所以無法正常序列化。
責(zé)任編輯:未麗燕 來源: 字節(jié)跳動(dòng)技術(shù)團(tuán)隊(duì)
相關(guān)推薦

2011-06-01 15:05:02

序列化反序列化

2009-08-24 17:14:08

C#序列化

2023-12-13 13:49:52

Python序列化模塊

2009-08-06 11:16:25

C#序列化和反序列化

2011-05-18 15:20:13

XML

2018-03-19 10:20:23

Java序列化反序列化

2009-06-14 22:01:27

Java對(duì)象序列化反序列化

2019-11-20 10:07:23

web安全PHP序列化反序列化

2009-08-25 14:24:36

C#序列化和反序列化

2011-06-01 14:50:48

2021-11-18 07:39:41

Json 序列化Vue

2009-09-09 16:10:11

.NET序列化和反序列

2012-04-13 10:45:59

XML

2009-08-25 14:43:26

C#序列化和反序列化

2009-09-09 14:45:41

XML序列化和反序列化

2009-09-09 15:47:27

XML序列化和反序列化

2010-03-19 15:54:21

Java Socket

2009-07-29 13:39:02

JSON序列化和反序列ASP.NET AJA

2016-09-21 00:15:27

2016-01-05 15:10:59

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)