## 前言
大家好,今天開始給大家分享 — Dubbo 專題之 Dubbo 序列化。在前一個章節中我們介紹了 Dubbo 路由規則之標簽路由,其實現原理為:如果消費端傳遞標簽則和配置的動態規則和靜態規則進行匹配,如果消費端未傳遞標簽則使用服務提供端的本地配置的靜態標簽和動態配置標簽進行匹配。同時我們也例舉了常見的使用場景並且進行了源碼解析來分析其實現原理。有的小伙伴可以想知道 Dubbo 中遠程調用數據傳輸是通過哪些方式進行數據的序列化呢?那么這個章節我們一起來討論在我們的 Dubbo 中有哪些序列化方式以及性能表現如何。下面就讓我們快速開始吧!
## 1. 序列化簡介
首先我們得明白什么是序列化和反序列化,舉個簡單的例子:當我們需要把一個數據對象寫入到文件或者在網絡中傳輸時,就要把數據對象進行轉換為二進制格式進行數據傳輸這個過程就叫做序列化,反之如果一個遠程數據或本地文件數據需要讀取並解析為我們的對象時就叫做反序列化。在 Dubbo RPC 中,同時支持多種序列化方式:
1. Dubbo 序列化:阿里尚未開發成熟的高效 Java 序列化實現,阿里不建議在生產環境使用它
2. Hessian2 序列化:Hessian 是一種跨語言的高效二進制序列化方式。但這里實際不是原生的 Hessian2 序列化,而是阿里修改過的Hessian Lite,它是 Dubbo RPC 默認啟用的序列化方式
3. Json 序列化:目前有兩種實現,一種是采用的阿里的 Fastjson 庫,另一種是采用 Dubbo中自己實現的簡單 Json庫,但其實現都不是特別成熟,而且 Json 這種文本序列化性能一般不如上面兩種二進制序列化。
4. Java 序列化:主要是采用 JDK 自帶的 Java 序列化實現,性能很不理想。
下圖是當前2.7.x版本中支持的序列化方式:

Dubbo RPC 默認采用 Hessian2 序列化。但 Hessian 是一個比較老的序列化實現了,而且它是跨語言的,所以不是單獨針對 Java 進行優化的。而 Dubbo RPC實際上完全是一種 Java to Java 的遠程調用,其實沒有必要采用跨語言的序列化方式。最近幾年,各種新的高效序列化方式層出不窮,不斷刷新序列化性能的上限,最典型的包括:
1. 專門針對Java語言的:Kryo、FST等等
2. 跨語言的:Protostuff、ProtoBuf、Thrift、Avro、MsgPack等等
其中,Kryo 是一種非常成熟的序列化實現,已經在Twitter、Groupon、Yahoo以及多個著名開源項目(如Hive、Storm)中廣泛的使用。而FST是一種較新的序列化實現,目前還缺乏足夠多的成熟使用案例。
## 2. 配置方式
下面我們主要通過 XML 方式進行配置介紹:
XML 方式
```xml
<dubbo:protocol name="dubbo" serialization="hession2"/>
```
這里使用`serialization`來進行序列化方式配置。
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<ins class="adsbygoogle"
style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-4279907681900931"
data-ad-slot="6812672741"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
## 3. 使用場景
根據前面的介紹我們大概理解了什么是序列化和反序列化,而序列化和反序列化在 Dubbo 中是必須的,那么 Dubbo 中提供了多種序列化方式我們應該使用哪一種序列化方式呢?我們先看一個來自官網的性能測試圖:

從上圖可以看出序列化方式:kyro、FST 性能最優。如果被序列化的類中不包含無參的構造函數,則在 Kryo 的序列化中,性能將會大打折扣,因為此時我們在底層將用 Java 的序列化來透明的取代 Kryo 序列化。所以,盡可能為每一個被序列化的類添加無參構造函數是一種最佳實踐。另外,Kryo 和 FST 本來都不需要被序列化都類實現 `Serializable` 接口,但我們還是建議每個被序列化類都去實現它,因為這樣可以保持和 Java 序列化以及 Dubbo 序列化的兼容性。
## 4. 示例演示
下面我以獲取圖書列表為例進行演示。項目結構如下:

我們主要看服務提供者端的`dubbo-provider-xml.xml`的 XML 配置 :
```xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--自定序列化方式為:hession2 -->
<dubbo:protocol port="20880" serialization="hession2"/>
<dubbo:application name="demo-provider" metadata-type="remote"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<bean id="bookFacade" class="com.muke.dubbocourse.serializable.provider.BookFacadeImpl"/>
<!--暴露服務為Dubbo服務-->
<dubbo:service interface="com.muke.dubbocourse.common.api.BookFacade" ref="bookFacade" />
</beans>
```
上面的配置文件中指定序列化方式為`hession2`。
## 5. 實現原理
下面我們通過源碼的方式簡單的分析它們的實現原理。下面我們直接到序列化的核心類`org.apache.dubbo.remoting.transport.CodecSupport`我們看其中的反序列化方法`deserialize`:
```java
public static ObjectInput deserialize(URL url, InputStream is, byte proto) throws IOException {
//獲取序列化對象
Serialization s = getSerialization(url, proto);
return s.deserialize(url, is);
}
```
我們繼續看看`getSerialization`方法:
```java
public static Serialization getSerialization(URL url, Byte id) throws IOException {
//通過協議查找Serialization對象
Serialization serialization = getSerializationById(id);
String serializationName = url.getParameter(Constants.SERIALIZATION_KEY, Constants.DEFAULT_REMOTING_SERIALIZATION);
//...
return serialization;
}
```
上面查找通過 SPI 注冊的所有序列化方式。我們接着`deserialize`方法看,這里我們以 Java JDK 提供的序列化方式為例:
```java
public ObjectInput deserialize(URL url, InputStream is) throws IOException {
return new JavaObjectInput(is);
}
```
可以看到這了通過 JDK 提供的 `JavaObjectInput` 對象包裝數據流。 其他的序列化方式也是類似,小伙伴可以自行分析。
## 6. 小結
在本小節中我們主要學習了 Dubbo 序列化,同時我們也分析了 Dubbo 中序列化的實現原理。其底層的實現原理就是利用我們的序列化和反序列化框架對數據對象進行操作,同時我們也介紹了當前針對 Java 序列化性能比較高的兩種方式,分別是:Kryo 和 FST。
本節課程的重點如下:
1. 理解 Dubbo 序列化和反序列化
2. 了解了序列化使用方式
3. 了解序列化框架性能
4. 了解序列化實現原理
#### 作者
> 個人從事金融行業,就職過易極付、思建科技、某網約車平台等重慶一流技術團隊,目前就職於某銀行負責統一支付系統建設。自身對金融行業有強烈的愛好。同時也實踐大數據、數據存儲、自動化集成和部署、分布式微服務、響應式編程、人工智能等領域。同時也熱衷於技術分享創立公眾號和博客站點對知識體系進行分享。關注公眾號:**青年IT男** 獲取最新技術文章推送!
**博客地址:** [http://youngitman.tech](http://youngitman.tech "http://youngitman.tech")
**微信公眾號:**
