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哦,害羞臉)....

相關文章
相關標籤/搜索