序列化(編碼)是將對象序列化為二進制形式(字節(jié)數(shù)組/有序字節(jié)流)槐瑞,主要用于網(wǎng)絡傳輸、數(shù)據(jù)持久化等阁苞,核心作用是對象狀態(tài)的保存與重建困檩。
反序列化(解碼)則是將從網(wǎng)絡、磁盤等讀取的字節(jié)數(shù)組/對象字節(jié)流還原成原始對象那槽,主要用于網(wǎng)絡傳輸對象的解碼悼沿,以便完成遠程調用。
為什么要序列化:
JVM是Java程序運行的環(huán)境骚灸,但是同時是一個操作系統(tǒng)的一個應用程序糟趾,即一個進程。運行依賴于內存,因此Java中對象都是存儲在內存中义郑,準確地說是JVM的堆或棧內存中蝶柿,可以各個線程之間進行對象傳輸,但是無法在進程之間進行傳輸非驮。如果涉及到跨內存的數(shù)據(jù)傳輸(比如兩臺機器的傳輸)交汤,直接把對象作為參數(shù)傳遞就不可取了,這時就需要通過“網(wǎng)絡”將數(shù)據(jù)傳輸劫笙。
序列化只是定義了拆解對象的具體規(guī)則芙扎,那這種規(guī)則肯定也是多種多樣的,常見的序列化方式有:
JDK 原生
JDK自帶的序列化方式填大,使用起來非常方便戒洼,只需要序列化的類實現(xiàn)了Serializable接口即可,Serializable接口沒有定義任何方法和屬性允华,所以只是起到了標識的作用圈浇,表示這個類是可以被序列化的。
把一個Java對象變?yōu)閎yte[]數(shù)組例获,需要使用ObjectOutputStream汉额。它負責把一個Java對象寫入一個字節(jié)流曹仗,如果沒有實現(xiàn)Serializable接口而進行序列化操作就會拋出NotSerializableException異常
在反序列化時榨汤,JVM需要知道所屬的class文件,在序列化的時候JVM會記錄class文件的版本號怎茫,也即serialVersionUID這一變量收壕。該變量默認是由JVM自動生成,也可以手動定義轨蛤。反序列化時JVM會按版本號找指定版本的class文件進行反序列化蜜宪,如果class文件有版本號在序列化和反序列化時不一致就會導致反序列化失敗,會拋異常提示版本號不一致祥山,
JDK序列化會把對象類的描述和所有屬性的元數(shù)據(jù)都序列化為字節(jié)流圃验,另外繼承的元數(shù)據(jù)也會序列化,所以導致序列化的元素較多且字節(jié)流很大缝呕,但是由于序列化了所有信息所以相對而言更可靠澳窑。但是如果只需要序列化屬性的值時就比較浪費。
而且因為Java的序列化機制可以導致一個實例能直接從byte[]數(shù)組創(chuàng)建供常,而不經(jīng)過構造方法摊聋,因此,它存在一定的安全隱患栈暇。一個精心構造的byte[]數(shù)組被反序列化后可以執(zhí)行特定的Java代碼麻裁,從而導致嚴重的安全漏洞。
Java默認提供的序列化:無法跨語言、序列化后的碼流太大煎源、序列化的性能差
XML
優(yōu)點:人機可讀性好色迂,可指定元素或特性的名稱。
缺點:序列化數(shù)據(jù)只包含數(shù)據(jù)本身以及類的結構薪夕,不包括類型標識和程序集信息脚草;只能序列化公共屬性和字段;不能序列化方法原献;文件龐大馏慨,文件格式復雜,傳輸占帶寬姑隅。
適用場景:當做配置文件存儲數(shù)據(jù)写隶,實時數(shù)據(jù)轉換。
JSON(跨語言)
一種輕量級的數(shù)據(jù)交換格式讲仰,
優(yōu)點:兼容性高慕趴、數(shù)據(jù)格式比較簡單,易于讀寫鄙陡、序列化后數(shù)據(jù)較小冕房,可擴展性好,兼容性好趁矾、與XML相比耙册,其協(xié)議比較簡單,解析速度比較快毫捣。
缺點:數(shù)據(jù)的描述性比XML差详拙、不適合性能要求為ms級別的情況、額外空間開銷比較大蔓同。
適用場景(可替代XML):跨防火墻訪問饶辙、可調式性要求高、基于Web browser的Ajax請求斑粱、傳輸數(shù)據(jù)量相對小弃揽,實時性要求相對低(例如秒級別)的服務。
JSON解析庫:Jackson
Jackson 是當前使用最廣泛的序列化和反序列化 Json的 Java 的開源框架则北。Spring MVC 的默認 Json 解析器便是 Jackson矿微。 解析大的 Json 文件速度比較快; 運行時占用內存比較低咒锻,性能比較好冷冗;Jackson 有靈活的 API,可以很容易進行擴展和定制惑艇。
Jackson提供了一套用于Java(和JVM平臺)的數(shù)據(jù)處理工具蒿辙,包括旗艦級流JSON解析器/生成器庫拇泛,匹配的數(shù)據(jù)綁定庫(與JSON之間的POJO)和附加的數(shù)據(jù)格式模塊。支持廣泛使用的數(shù)據(jù)類型的數(shù)據(jù)類型思灌。
三大模塊:
Streaming流處理模塊(jackson-core):定義底層處理流的API:JsonPaser和JsonGenerator等俺叭,并包含「特定于json」的實現(xiàn)。
Annotations標準注解模塊(jackson-annotations):包含標準的Jackson注解
Databind數(shù)據(jù)綁定模塊(jackson-databind):在streaming包上實現(xiàn)數(shù)據(jù)綁定(和對象序列化)支持泰偿;「它依賴于上面的兩個模塊」熄守,也是Jackson的高層API(如ObjectMapper)所在的模塊
Jackson-core Github地址:https://github.com/FasterXML/jackson-core
Jackson-core 官方文檔:https://github.com/FasterXML/jackson-core/wiki
Jackson-annotations Github地址:https://github.com/FasterXML/jackson-annotations
Jackson-annotations 官方文檔:https://github.com/FasterXML/jackson-annotations/wiki
Jackson-databind Github地址:https://github.com/FasterXML/jackson-databind
Jackson-databind 官方文檔:https://github.com/FasterXML/jackson-databind/wiki
官網(wǎng):http://fasterxml.com/
JSON解析庫:Gson
Google Gson是一個簡單的基于Java的庫,用于將Java對象序列化為JSON
Github地址:https://github.com/google/gson
官方文檔:https://github.com/google/gson/blob/master/UserGuide.md
API文檔:https://www.javadoc.io/doc/com.google.code.gson/gson
JSON解析庫:Fastjson(安全漏洞較多)
Fastjson是阿里巴巴的開源JSON解析庫耗跛,它可以解析JSON格式的字符串裕照,支持將Java Bean序列化為JSON字符串,也可以從JSON字符串反序列化到JavaBean调塌。
Fastjson1 Github地址:https://github.com/alibaba/fastjson
Fastjson1 官方文檔:https://github.com/alibaba/fastjson/wiki/
Fastjson2 Github地址:https://github.com/alibaba/fastjson2
Fastjson2 官方文檔:https://github.com/alibaba/fastjson2/wiki
Kryo
快速序列化/反序列化工具晋南,依賴于字節(jié)碼生成機制(底層使用了 ASM 庫),在序列化速度上有一定的優(yōu)勢羔砾,正因如此也只能限制在基于 JVM 的語言上负间。
Kryo支持自動深/淺拷貝,直接通過對象->對象的深度拷貝姜凄,而不是對象->字節(jié)->對象的過程政溃。
Kryo 序列化出的結果是其自定義的、獨有的一種格式态秧。由于其序列化出的結果是二進制的董虱,也即 byte[],因此像 Redis 這樣可以存儲二進制數(shù)據(jù)的存儲引擎是可以直接將 Kryo 序列化出來的數(shù)據(jù)存進去屿聋。
Github地址:https://github.com/EsotericSoftware/kryo
官方文檔:https://github.com/EsotericSoftware/kryo/wiki
社區(qū):https://groups.google.com/g/kryo-users
ProtoBuf(跨語言)
谷歌開發(fā)的一款無關平臺空扎,無關語言藏鹊,可擴展润讥,輕量級高效的序列化結構的數(shù)據(jù)格式,用于將自定義數(shù)據(jù)結構序列化成字節(jié)流盘寡,和將字節(jié)流反序列化為數(shù)據(jù)結構楚殿。
適合做數(shù)據(jù)存儲和為不同語言,不同應用之間互相通信的數(shù)據(jù)交換格式竿痰,只要實現(xiàn)相同的協(xié)議格式脆粥,后綴為proto文件被編譯成不同的語言版本,這樣不同的語言可以解析其它語言通過Protobuf序列化的數(shù)據(jù)影涉。
優(yōu)點:
1.跨語言:可以在多種語言之間交換結構化數(shù)據(jù)变隔。
2.向后兼容,新增的字段不影響協(xié)議使用蟹倾。
3.自動化生成代碼匣缘,簡單易用猖闪。
4.二進制消息,效率高肌厨,性能好培慌。(PS:解析速度快、占用空間少)
5.Netty等框架集成了該協(xié)議柑爸,提高開發(fā)效率吵护。
6.安全,只寫入了字段號信息表鳍,被編碼成二進制馅而,破解難度大。
缺點:
1.二進制消息譬圣,可讀性差用爪。
2.字段冗余,類會越來越大胁镐,維護成本高偎血。
Github地址:https://github.com/protocolbuffers/protobuf
官網(wǎng):https://developers.google.com/protocol-buffers/
官方文檔:https://developers.google.com/protocol-buffers/docs/overview
API文檔:https://developers.google.com/protocol-buffers/docs/reference/overview
Thrift(跨語言)
高效的、支持多種語言的遠程服務調用框架盯漂,由于Thrift提供了多語言之間的RPC服務颇玷,所以很多時候被用于序列化中。
優(yōu)點:
1.序列化和RPC支持一站式解決就缆,比ProtoBuf更方便 帖渠。
2.豐富的數(shù)據(jù)類型、對于數(shù)據(jù)字段的增刪具有較強的兼容性竭宰、支持二進制壓縮編碼空郊。
3.跨語言,IDL接口定義語言切揭,自動生成多語言文件 狞甚。
省流量,體積較小 廓旬。
4.包含完整的客戶端/服務端堆棧哼审,可快速實現(xiàn)RPC 。
5.為服務端提供了多種工作模式孕豹,如線程池模型涩盾、非阻塞模型。
缺點:
1.不支持雙通道 励背。
2.rpc方法非線程安全春霍,服務器容易被掛死,需要串行化叶眉。
3.默認不具備動態(tài)特性(可以通過動態(tài)定義生成消息類型或者動態(tài)編譯支持)
適用場景:分布式系統(tǒng)的RPC解決方案
Github地址:https://github.com/apache/thrift
官網(wǎng):https://thrift.apache.org/
官方文檔:hhttps://thrift.apache.org/docs/
Hessian(跨語言)
Hessian與Protobuf址儒、Thrift一樣籍胯,支持跨語言RPC通信。Hessian相比其它跨語言PRC框架的一個主要優(yōu)勢在于离福,它不是采用IDL來定義數(shù)據(jù)和服務杖狼,而是通過自描述來完成服務的定義。
Hessian 是一種動態(tài)類型妖爷、二進制序列化和 Web 服務協(xié)議蝶涩,專為面向對象的傳輸而設計。和JDK自帶的序列化方式類似絮识,Hessian采用的也是二進制協(xié)議绿聘,Hessian序列化之后,字節(jié)數(shù)更小次舌,性能更優(yōu)熄攘。
Github地址:https://github.com/ebourg/hessian
官網(wǎng):http://hessian.caucho.com/
官方文檔:http://hessian.caucho.com/doc/
Avro(跨語言)
Avro是Apache Hadoop下的一個數(shù)據(jù)序列化框架。用于支持數(shù)據(jù)密集型應用彼念,很適合遠程或本地大規(guī)模數(shù)據(jù)交換和存儲挪圾,解決了JSON的冗長和沒有IDL的問題。
優(yōu)點:支持豐富的數(shù)據(jù)類型逐沙、簡單的動態(tài)語言結合功能哲思、具有自我描述屬性、提高了數(shù)據(jù)解析速度吩案、快速可壓縮的二進制數(shù)據(jù)形式棚赔、可以實現(xiàn)遠程過程調用RPC、支持跨編程語言實現(xiàn)徘郭。
缺點:對于習慣于靜態(tài)類型語言的用戶不直觀靠益。
適用場景:在Hadoop中做Hive、Pig和MapReduce的持久化數(shù)據(jù)格式残揉。
Github地址:https://github.com/apache/avro
官網(wǎng):https://avro.apache.org/
官方文檔:https://avro.apache.org/docs/current/
MessagePack(跨語言)
一個高效的二進制序列化框架胧后,支持不同語言間的數(shù)據(jù)交換,性能更快冲甘,序列化之后的碼流也更小绩卤。
優(yōu)點:
1.跨語言途样,多語言支持江醇。
2.序列化反序列化效率高,文件體積小何暇,比Json小一倍陶夜。
3.兼容json數(shù)據(jù)格式
缺點:
1.缺乏復雜模型支持。msgpack對復雜的數(shù)據(jù)類型(List裆站、Map)支持的不夠条辟,序列化沒有問題黔夭,但是反序列化回來就很麻煩,尤其是對于java開發(fā)人員羽嫡。
2.維護成本較高本姥。msgpack通過value的順序來定位屬性的,需要在不同的語言中都要維護同樣的模型以及模型中屬性的順序杭棵。
3.不支持模型嵌套婚惫。msgpack無法支持在模型中包含和嵌套其他自定義的模型(如weibo模型中包含comment的列表)。
Github地址:https://github.com/msgpack
官網(wǎng):https://msgpack.org/
官方文檔:https://msgpack.org/
影響序列化性能的關鍵因素:
序列化后的碼流大谢曜Α(網(wǎng)絡帶寬的占用)
序列化的性能(CPU資源占用)
是否支持跨語言(異構系統(tǒng)的對接和開發(fā)語言切換)