一緒にDubboを書きます.Kryoシーケンス化


この記事は私のブログ、住所に掲載されています.https://blog.guoziyang.top/archives/65/、プロジェクトアドレス:https://github.com/CN-GuoZiyang/My-RPC-Framework
本明細書に対応するcommitは166 a 6 d 1であり、完全なプロジェクトディレクトリである.
前節では,一般的なシーケンス化フレームワークを実現し,シーケンス化方式の拡張性を高め,JSONベースのシーケンス化器を実現した.
しかし、JSONベースのこのシーケンサには、あるクラスの属性を逆シーケンス化する場合、属性がObjectと宣言されると逆シーケンス化エラーが発生し、通常、Object属性をStringタイプに直接逆シーケンス化するため、他のパラメータがシーケンス化を支援する必要があるという欠点もある.また、JSONシーケンサは文字列(JSON列)に基づいており、占有スペースが大きく速度が遅い.
この節では,Kryoベースのシーケンス化器を実現する.では、Kryoとは何ですか.
Kryoは高速で効率的なJavaオブジェクトのシーケンス化フレームワークであり、主な特徴は高性能、効率的、使いやすいことです.最も重要な2つの特徴は、1つはバイトのシーケンス化に基づいて、空間利用率が高く、ネットワーク伝送時に体積を減らすことができることである.2つ目は、シーケンス化時に属性オブジェクトのタイプ情報を記録することであり、逆シーケンス化時に以前の問題が発生しないようにします.
実装インタフェース
まずkryoの依存を追加
        <dependency>
            <groupId>com.esotericsoftwaregroupId>
            <artifactId>kryoartifactId>
            <version>4.0.2version>
        dependency>

前節では、一般的なシーケンス化インタフェースを定義しました.
public interface CommonSerializer {

    byte[] serialize(Object obj);

    Object deserialize(byte[] bytes, Class<?> clazz);

    int getCode();

    static CommonSerializer getByCode(int code) {
        switch (code) {
            case 1:
                return new JsonSerializer();
            default:
                return null;
        }
    }
}

ここではKryoの番号を0に設定し,その後はデフォルトのシーケンス化器として静的メソッドのswitchにcaseを1つ追加すればよい.
インタフェースによると、私たちの主な任務は、serialize()deserialize()の2つの方法を実現することです.以下のようにします.
public class KryoSerializer implements CommonSerializer {

    private static final Logger logger = LoggerFactory.getLogger(KryoSerializer.class);

    private static final ThreadLocal<Kryo> kryoThreadLocal = ThreadLocal.withInitial(() -> {
        Kryo kryo = new Kryo();
        kryo.register(RpcResponse.class);
        kryo.register(RpcRequest.class);
        kryo.setReferences(true);
        kryo.setRegistrationRequired(false);
        return kryo;
    });

    @Override
    public byte[] serialize(Object obj) {
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             Output output = new Output(byteArrayOutputStream)){
            Kryo kryo = kryoThreadLocal.get();
            kryo.writeObject(output, obj);
            kryoThreadLocal.remove();
            return output.toBytes();
        } catch (Exception e) {
            logger.error("         :", e);
            throw new SerializeException("         ");
        }
    }

    @Override
    public Object deserialize(byte[] bytes, Class<?> clazz) {
        try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            Input input = new Input(byteArrayInputStream)) {
            Kryo kryo = kryoThreadLocal.get();
            Object o = kryo.readObject(input, clazz);
            kryoThreadLocal.remove();
            return o;
        } catch (Exception e) {
            logger.error("          :", e);
            throw new SerializeException("          ");
        }
    }

    @Override
    public int getCode() {
        return SerializerCode.valueOf("KRYO").getCode();
    }
}

ここでKryoはスレッドセキュリティの問題がある可能性があります.ドキュメント上ではThreadLocalに置くことをお勧めします.1つのスレッドに1つのKryoがあります.シーケンス化では、まずOutputオブジェクト(Kryoフレームワークの概念)を作成し、次にwriteObjectメソッドを使用してオブジェクトをOutputに書き込み、最後にOutputオブジェクトのtoByte()メソッドを呼び出すと、オブジェクトのバイト配列が得られます.逆シーケンス化はInputオブジェクトから直接readObjectであり,ここでは各属性のタイプ情報を具体的に伝達する必要はなく,伝達オブジェクトのタイプのみが必要である.
最後にgetCodeメソッドでは、シーケンス化された番号が列挙クラスSerializerCodeに書かれています.
public enum SerializerCode {
    KRYO(0),
    JSON(1);
    private final int code;
}

シーケンサを置き換えてテスト
NettyServerとNettyClient責任チェーンのCommonEncoderから入力されたパラメータをKryoSerializerに変更するだけで、Kryoシーケンス化を使用できます.
-                             pipeline.addLast(new CommonEncoder(new JsonSerializer()));
+                             pipeline.addLast(new CommonEncoder(new KryoSerializer()));

最後に前のテストを実行し、テスト結果は前と同じで問題ありません.