精通并发与 Netty (二)常用的 rpc 框架

编辑:Discuz论坛 发布于2019-07-10 09:21

Google Protobuf 使用方式分析

对于 RPC 协议来说,最重要的就是对象的发送与接收,这就要用到序列化与反序列化,也称为编码和解码,序列化与反序列化和网络传输一般都在对应的 RPC 框架中完成。

序列化与反序列化的流程如下:

JavaBean-> stub(client) <->skeleton(server)->JavaBean,简单点说就是编码和解码。

相比于 RMI 远程方法调用,很多 RPC 远程过程调用的跨语言的,这就需要序列化于反序列化协议也支持跨语言。Google Procobuf 就是这样一种跨语言的序列化于反序列化协议,效率非常高(怎么做到比其他协议效率高那?比其他协议压缩生成的对象小)。

Netty 对于 ProtoBuf 提供了很好的支持。

先看如何单独使用 Google ProtoBuf

  1. 新建 .proto 结构描述文件

    syntax = "proto2";
    
    package com.paul.protobuf;
    
    //加快解析速度
    option optimize_for = SPEED;
    option java_package = "com.paul.protobuf";
    option java_outer_classname = "DataInfo";
    
    message Student{
      reuqired string name = 1;
      option int32 = 2;
      option string address = 3;
    }
  2. 使用对应的编译文件生成对应的 Java 类

    Proton —java_out src/main/java src/protobuf/Student.proto

  3. 这时在我们代码的 src/main/java 文件夹下生成了一个新的 pkg com.paul.protobuf,里面生成了 DataInfo 类。对象会有对应的 builder 方法让我们来构建。

  4. 测试序列化方法

    // 构建对象->字节->对象
    public class ProtoBufTest{
      public static void main(String[] args) throws Exception{
        DataInfo.Student student = DataInfo.Student.newBuilder().setName("张三").setAge(20).setAddress("abc").build();
        byte[] student2ByteArray = student.toByteArray();
        DataInfo.Student student2 = DataInfo.Student.parseFrom(student2ByteArray);
        System.out.println(studdent2);
      }
    
    }

在来看 Netty 对 Google ProtoBuf 的支持

还是只给出不一样的部分(服务单和客户端的这部分是一样的):

@Override
protected void initChannel(SocketChannel ch) throws Exception{
  ChannelPipeline pipeline = ch.pipeline();
  pipeline.addLast(new ProtobufVarint32FrameDecoder());
  //解码器
  pipeline.addLast(new ProtobufDecoder(DataInfo.Student.getDefaultInstance()));
  pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
  //编码器
  pipeline.addLast(new ProtobufEncoder());
  pipeline.addLast(new MyServerHandler());
}

测试方法就是在客户端组装一个 DataInfo.Student 然后发送给服务端,这里就不演示了。

大家可能会发现上面的代码存在一个问题,就是上面的程序只能对 DataInfo.Student 进行编解码,如果传递消息的类型有多种怎么办那?