SpringBoot整合Netty并使用Protobuf进行数据传输

我只是给代码注入灵魂;java

官方地址: github.com/google/prot…python

高效的编码方式 Google Protocolgit

咱们在编写网络应用程序的时候须要注意codec(编解码器),由于数据在网络中传输的都是二进制字节码数据,而咱们拿到的目标数据每每
不是字节码数据,所以在发送数据时就须要编码,收到数据时须要解码
codec 的组成部分有两个:decoder(解码器)和encoder(编码器)。encoder 负责把业务数据转换成字节码数据,decoder 负责把字节码数据转换成业务数据。
其实Java 的序列化技术就能够做为codec 去使用,可是它的硬伤太多:
    1. 没法跨语言,这应该是Java 序列化最致命的问题了。
    2. 序列化后的体积太大,是二进制编码的5 倍多。
    3. 序列化性能过低。
因为Java 序列化技术硬伤太多,所以Netty 自身提供了一些codec,以下所示:
Netty 提供的解码器:
    1. StringDecoder, 对字符串数据进行解码
    2. ObjectDecoder,对Java 对象进行解码
Netty 提供的编码器:
    1. StringEncoder,对字符串数据进行编码
    2. ObjectEncoder,对Java 对象进行编码
Netty 自己自带的ObjectDecoder 和ObjectEncoder 能够用来实现POJO 对象或各类业务对象的编码和解码,但其内部使用的还是Java 序列化技术,因此咱们不建议使用。所以对
于POJO 对象或各类业务对象要实现编码和解码,咱们须要更高效更强的技术。 
复制代码

Google 的Protocol(Google出品必然牛x)github

Protocol 是Google 发布的开源项目,全称Google Protocol Buffers,特色以下:编程

  • 支持跨平台、多语言(支持目前绝大多数语言,例如C++、C#、Java、python 等)
  • 高性能,高可靠性
  • 使用Protocol 编译器能自动生成代码,Protocol 是将类的定义使用.proto 文件进行描述,而后经过protoc.exe 编译器根据.proto 自动生成.java 文件

1, 首先是安装 2, 使用:windows

  • 2.1 引入Protocol的依赖
<dependency>
           <groupId>com.google.protobuf</groupId>
           <artifactId>protobuf-java</artifactId>
           <version>3.5.1</version>
       </dependency>
复制代码
  • 2.2 定义本身的协议格式服务器

    接着是须要按照官方要求的语法定义本身的协议格式。网络

    好比我这里须要定义一个输入输出的报文格式: MessageRequestBase.proto多线程

    syntax = "proto3"; // (1)
    
    option java_package = "cn.haoxiaoyong.record.proto.protobuf";//(2)
    option java_outer_classname = "MessageRequestBase";//(3)
    
    message MessageRequest {//(4)
    string requestId = 1;//(5)
    string content = 2;
    }
    复制代码

(1): 版本号,protobuf语法有 proto2和proto3两种,这里指定 proto3并发

(2): 指定包名

(3): 设置生成的Java类名

(4): 内部类的类名,真正的POJO

(5): 设置类中的属性,符号后是序号,不是属性值

注意个文件名MessageRequestBase.proto必须是 .proto后缀

MessageResponseBase.proto:

syntax = "proto3";
option java_package = "cn.haoxiaoyong.record.proto.protobuf";
option java_outer_classname = "MessageResponseBase";

message MessageResponse {
    int32 code = 1;
    string content = 2;
    string msg = 3;
}
复制代码

以上同理,其中string,int32,是这个字段的类型,更多类型参考官方文档,基本上java中的数据类型都包含了,其中还包含了枚举(enum)类型;

  • 2.3 安装成功以后,经过protoc.exe 根据描述文件(.proto)生成Java 类,具体操做以下所示:
    • 进入 MessageRequestBase.proto,MessageResponseBase.proto这两个文件所在的目录;
    • 执行 protoc --java_out=/tmp MessageRequestBase.proto MessageResponseBase.proto,生成的 java类就会在 /tmp 文件夹下;固然这个目录能够改成其余的.(若是你是windows电脑就能够指定在C盘下或者D盘下,看心情。。)
    • 将这两个 java 类拷贝到项目中,这两个类咱们不要编辑它,直接拿着用便可,该类内部有一个内部类,这个内部类才是真正的POJO,必定要注意。
  • 2.4在项目中使用,Netty 已经自带了对 Google protobuf 的编解码器,也是只须要在 pipline 中添加便可。

Client:

public class ClientHandlerInitilizer extends ChannelInitializer<Channel> {
    @Override
    protected void initChannel(Channel ch) throws Exception {
        ch.pipeline()
        	// google Protobuf 编解码
                .addLast(new ProtobufDecoder(MessageResponseBase.MessageResponse.getDefaultInstance()))
                .addLast(new ProtobufEncoder())
                .addLast(new NettyClientHandler());
    }
}
复制代码

上述代码在编写客户端程序时,要向Pipeline 链中添加ProtobufEncoder 编码器对象。

@RequestMapping("/send")
    public String send(@RequestBody RestInfo restInfo) {
        MessageRequestBase.MessageRequest message = new MessageRequestBase.MessageRequest()
                .toBuilder()
                .setContent(restInfo.getStr())
                .setRequestId(UUID.randomUUID().toString()).build();
        //异步执行
        nettyClient.sendMsg(message);
        return "send ok";
    }
复制代码

上述代码在往服务器端发送(POJO)时就能够使用生成的MessageRequestBase类搞定,很是方便。 Server:

public class NettyServerHandlerInitializer extends ChannelInitializer<Channel> {
    @Override
    protected void initChannel(Channel ch) throws Exception {

        ch.pipeline()
                .addLast(new ProtobufDecoder(MessageRequestBase.MessageRequest.getDefaultInstance()))
                .addLast(new ProtobufEncoder())
                .addLast(new NettyServerHandler());
    }
}
复制代码

上述代码在编写服务器端程序时,要向Pipeline 链中添加ProtobufDecoder 解码器对象。

稍微注意的是,在构建 ProtobufDecoder 时须要显式指定解码器须要解码成什么类型。在服务端MessageRequestBase.MessageRequest.getDefaultInstance(),在客户端MessageResponseBase.MessageResponse.getDefaultInstance()

@Override
    protected void channelRead0(ChannelHandlerContext ctx, MessageRequestBase.MessageRequest msg) throws Exception {
        if (msg.getContent() != null) {
            log.info("收到客户端的业务消息:{}",msg.toString());
            //在这里作一些业务处理操做。。。
            String converter = NettyServerHandler.converter.converterTask(msg);
            log.info("server 拿处处理后的返回结果 :{}",converter);
            MessageResponseBase.MessageResponse response = MessageResponseBase.MessageResponse.newBuilder()
                    .setCode(200)
                    .setContent(converter)
                    .setMsg("success")
                    .build();
            ctx.writeAndFlush(response);
        }
    }
复制代码

上述代码在服务器端接收数据时,直接就能够把数据转换成 pojo 使用,很是方便

结束了吗...No... (看看了时间已经将近零点了,该睡了,看博客你也不要熬夜,注意身体,加油!)

本文介绍了Netty中使用Protobuf的编码解码;下篇文件将介绍使用Protobuf解决粘包拆包

使用方式

1,启动:NettyApplication 2,使用postman或者其余工具请求:

在这里插入图片描述
控制台打印:
在这里插入图片描述

demo 地址:

当前项目:Netty框架--netty编码解码(项目中proto包下)

多线程并发编程(项目中thread包下)

BIO编程(项目中bio包下)

NIO编程(项目中nio包下)

自定义RPC(项目中rpc包下)

欢迎给个小星星鼓励一下(记得Star哦,害羞脸)....

相关文章
相关标签/搜索