簡易RPC框架:序列化機制

beanlam發表於2019-01-19

概述

在上一篇文章《簡易RPC框架:基於 netty 的協議編解碼》中談到對於協議的 decode 和 encode,在談 decode 之前,必須先要知道 encode 的過程是什麼,它把什麼東西轉化成了二進位制協議。
由於我們還未談到具體的 RPC 呼叫機制,因此暫且認為 encode 就是把一個包含了呼叫資訊的 Java 物件,從 client 經過序列化,變成一串二進位制流,傳送到了 server 端。
這裡需要明確的是,encode 的職責是拼協議,它不負責序列化,同樣,decode 只是把整個二進位制報文分割,哪部分是報文頭,哪部分是報文體,誠然,報文體就是被序列化成二進位制流的一個 Java 物件。
對於呼叫方來說,先將呼叫資訊封裝成一個 Java 物件,經過序列化後形成二進位制流,再經過 encode 階段,拼接成一個完整的遵守我們定好的協議的報文。
對於被呼叫方來說,則是收取完整的報文,在 decode 階段將報文中的報文頭,報文體分割出來,在序列化階段將報文體反序列化為一個 Java 物件,從而獲得呼叫資訊。
本文探討序列化機制。

基於 netty handler

由於這個 RPC 框架基於 netty 實現,因此序列化機制其實體現在了 netty 的 pipeline 上的 handler 上。
例如對於呼叫方,它需要在 pipeline 上加上一個 序列化 encode handler,用來序列化發出去的請求,同時需要加上一個反序列化的 decode handler, 以便反序列化呼叫結果。如下所示:

                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new ProtocolEncoder())
                                .addLast(new ProtocolDecoder())
                                .addLast(new SerializationHandler(serialization))
                                .addLast(new DeserializationHandler(serialization));

                    }

其中的 SerializationHandler 和 DeserializationHandler 就是上文提到的序列化 encode handler 和反序列化 decode handler。
同樣,對於被呼叫方來說,它也需要這兩個handler,與呼叫方的 handler 編排順序一致。

其中,serialization 這個引數的物件代表具體的序列化機制策略。

序列化機制

上文中,SerializationHandler 和 DeserializationHandler 這兩個物件都需要一個 serialization 物件作為引數,它是這麼定義的:

private ISerialization serialization = SerializationFactory.getSerialization(ServerDefaults.DEFAULT_SERIALIZATION_TYPE);

採用工廠模式來建立具體的序列化機制:

/**
 * 序列化工廠
 *
 * @author beanlam
 * @version 1.0
 */
public class SerializationFactory {

    private SerializationFactory() {
    }

    public static ISerialization getSerialization(SerializationType type) {
        if (type == SerializationType.JDK) {
            return new JdkSerialization();
        }
        return new HessianSerialization();
    }
}

這裡暫時只支援 JDK 原生序列化 和 基於 Hessian 的序列化機制,日後若有其他效率更高更適合的序列化機制,則可以在工廠類中進行新增。

這裡的 hessian 序列化是從 dubbo 中剝離出來的一塊程式碼,感興趣可以從 dubbo 的原始碼中的 com.caucho.hessian 包中獲得。

以 HessianSerialization 為例:

/**
 * @author beanlam
 * @version 1.0
 */
public class HessianSerialization implements ISerialization {

    private ISerializer serializer = new HessianSerializer();
    private IDeserializer deserializer = new HessianDeserializer();

    @Override
    public ISerializer getSerializer() {
        return serializer;
    }

    @Override
    public IDeserializer getDeserializer() {
        return deserializer;
    }

    @Override
    public boolean accept(Class<?> clazz) {
        return Serializable.class.isAssignableFrom(clazz);
    }
}

根據 Hessian 的 API, 分別返回一個 hessian 的序列化器和反序列化器即可。

相關文章