使用 httputils + protostuff 實現高效能 rpc

带刺的坐椅發表於2024-12-05

1、先講講 protobuf

protobuf 一直是高效能序列化的代表之一(google 出品)。但是用起來,可難受了,你得先申明 “.proto” 配置檔案,並且要把這個配置檔案編譯轉成類。所以必然要學習新語法、新工具。

可能真的太難受了!於是乎,(有不爽的人)搞了個有創意的框架 protostuff(“buf” 變成 "stuff")。它借用註解,替代了 “.proto” 檔案申明和生成類的過程,豐常的接地氣。

2、再講講 rpc

一講 rpc ,很多人會想到 dubbo (國產)和 grpc。估計還會聯想到註冊與發現服務;可能還會聯想到微服務。可能就會覺得這個事兒“老重啦”,害怕!

其實很簡單的,你請求一次 http 就是個 rpc 請求了(遠端過程呼叫嘛)。最典型的就是 http + json 請求了。

3、現在講 httputils + protostuff

這裡我們會用到兩個重要的 solon 框架的外掛:一個是 httputils 工具外掛,一個是 protostuff 序列化外掛。

<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-serialization-protostuff</artifactId>
</dependency>

<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-net-httputils</artifactId>
</dependency>

這裡要感謝 solon 框架,它強調三元合一(mvc 與 rpc 是自然一體的)。下面,開始幹活啦...

  • 公用包(也可以在客戶端,服務端分別定義實體類。只要 @Tag 順序與型別對應上即可 )

這裡定義一個 protostuff 實體類。注意 @Tag 註解,它是替代 “.proto” 配置檔案的關鍵。

@Setter
@Getter
public class MessageDo {
    @Tag(1)    // Protostuff 註解,順序位從 1 開始
    private long id;
    @Tag(2)
    private String title;
}
  • 服務端(只支援 @Body 資料接收,只支援實體類)

在 solon web 專案裡,新增一個控制器(註解可以用 @Remoting@Controller)。使用 @Remoting 時,方法上不需要加 @Mapping 註解。

#新增外掛
org.noear:solon-web
org.noear:solon-serialization-protostuff
@Mapping("/rpc/demo")
@Remoting
public class HelloServiceImpl {
    @Override
    public MessageDo hello(@Body MessageDo message) { //還可接收路徑變數,與請求上下文
        return message;
    }
}
  • 客戶端應用 for HttpUtils(只支援 body 資料提交,只支援實體類)
#新增外掛
org.noear:solon-net-httputils
//應用程式碼
@Component
public class DemoCom {
    public MessageDo hello() {
        MessageDo message = new MessageDo();
        message.setId(3);
        
        //指明請求資料為 PROTOBUF,接收資料要 PROTOBUF
        return HttpUtils.http("http://localhost:8080/rpc/demo/hello")
                .serializer(ProtostuffBytesSerializer.getInstance())
                .header(ContentTypes.HEADER_CONTENT_TYPE, ContentTypes.PROTOBUF_VALUE)
                .header(ContentTypes.HEADER_ACCEPT, ContentTypes.PROTOBUF_VALUE)
                .bodyOfBean(message)
                .postAs(MessageDo.class);
    }
}

4、總結

總體上,跟 json 沒什麼大的區別。主要是指定了:序列化器、內容型別、接收型別,讓各端能識別類據型別。

5、還可以使用“註解式 http 客戶端”框架

肯定也會有人覺得,一個介面還好,如果有很多介面就要寫很多重複的http請求程式碼了。所以,“註解式 http 客戶端” 很重要,這也是很多 rpc 框架流行的原因,就像呼叫本地介面一樣,使用遠端介面。

nami 是 solon 框架的 rpc 客戶端(或者,註解式 http 客戶端),支援各種序列化。(只要是“支援序列化定製”的註解式 http 客戶端,都可用!)

  • 新增兩個依賴包
#新增外掛
org.noear:nami-coder-protostuff # protostuff 編解碼支援
org.noear:nami-channel-http     # http 請求通道支援,也可以是 socketd(支援 tcp, udp, ws)
  • 程式碼應用(只支援 body 資料提交,只支援實體類)
@NamiClient(url = "http://localhost:8080/rpc/demo", headers = {ContentTypes.PROTOBUF, ContentTypes.PROTOBUF_ACCEPT})
public interface HelloService {
    MessageDo hello(@NamiBody MessageDo message);
    //方法2
    //方法3
    //方法4
    //方法5
    //方法6
}

@Component
public class DemoCom {
    @NamiClient //注入
    HelloService helloService;
  
    public MessageDo hello() {
         MessageDo message = new MessageDo();
         message.setId(3);
        
         rerturn helloService.hello(message);
    }
}

相關文章