RSocket 入門:Spring Boot 伺服器

工程 | Ben Wilcock | 2020 年 3 月 2 日 | ...

時間:約 15 分鐘。

在多樣化的微服務世界中,HTTP 是代理間通訊的無可爭議的領導者。它成熟、完善且無處不在。但在某些情況下,HTTP 請求-響應可能會很麻煩。如果您需要超越傳統請求-響應的通訊模式,例如即發即棄或流式傳輸,該怎麼辦?如果您想雙向傳送訊息,又該怎麼辦?

使用 HTTP 也可以實現類似功能,但這並非該協議的初衷。許多解決方案都會帶來額外的權衡或不足。此外,沒有“必須始終使用 HTTP”的硬性規定,AMQP 等訊息協議已經證明了這一點。所以,瞭解你的選擇是好的,並且時不時地在你的列表中新增一些新技術也是健康的。本文將介紹 RSocket 這個替代方案。

RSocket 是一種新的訊息傳遞協議,旨在解決一些常見的微服務通訊挑戰。RSocket 提供了一個靈活的協議,可以在 TCP 或 WebSockets 上執行。這意味著你可以進行二進位制訊息傳輸而無需轉換。你將獲得多路複用、背壓、連線恢復和路由等現代化控制功能,以及請求-應答、傳送即忘和流式傳輸等多種訊息模式。RSocket 也完全是響應式的,因此非常適合你的高吞吐量微服務應用程式。早期採用者包括 Netflix、Pivotal、阿里巴巴和 Facebook,它們都是提供可擴充套件網際網路服務的專家。

在這篇文章(這是一個系列的第一篇)中,你將學習如何開始使用 RSocket。你將熟悉它的工作原理,並體驗它的一些強大功能。在本系列結束時,你將把 RSocket 新增到你的技能集中,以便下次你在考慮選擇時,將多一個協議可供選擇。

開始吧...

由於請求-響應對於大多數 Web 開發人員來說是熟悉的領域,我們將從這個模式開始我們的 RSocket 之旅。請求-響應的語義相當直接,你傳送一個請求,然後得到一個響應。HTTP 就是建立在這種基本互動之上的,而且它非常常見。

在本教程中,你將學習如何使用 Spring Boot 作為伺服器,終端應用程式作為客戶端,透過 RSocket 進行請求-響應。

請求-響應只是 Spring 和 RSocket 支援的四種互動模型之一。我們將在未來的文章中介紹其他模型。

當你按照下面的步驟操作時,你會發現使用 Spring Boot 構建 RSocket 伺服器所需的程式碼量非常小。程式碼已為你提供在此,但如果你願意,也可以在幾分鐘內從頭開始編寫程式碼。

步驟 1:設定你的環境

首先,檢查你是否安裝了以下必備條件:

  1. 版本 8 或更高版本的 Java SDK(要檢查,請在終端中使用 java -version)
  2. 一個可用的Java IDE(我使用的是 IntelliJ IDEA)
  3. 一個包含克隆或解壓的演示程式碼示例的資料夾。
  4. Linux Bash/ZSH shell(如果你是 Windows 使用者,請檢視下面的注意事項)

如果你是 Windows 使用者,請切換到 Microsoft 的適用於 Linux 的 Windows 子系統。Microsoft 關於如何執行此操作的說明在此

現在,將下載的專案資料夾設為終端中的當前目錄

cd spring-rsocket-demo

接下來,將由 Toshiaki Maki 編寫的優秀 RSocket Client CLI 下載到你克隆或解壓的程式碼的 rsocket-server 資料夾中。還有一個官方的 RSocket CLI 在其他地方,但 Toshiaki 的 CLI 更易於使用。在終端中,按如下方式下載 JAR 檔案:

cd rsocket-server
wget -O rsc.jar https://github.com/making/rsc/releases/download/0.4.2/rsc-0.4.2.jar

你稍後將使用此客戶端與 RSocket 伺服器通訊,但現在,透過呼叫幫助命令來測試它是否正常工作,如下所示:

java -jar rsc.jar --help

你應該看到如下所示的一些輸出(我已截斷),解釋了命令的用法和選項。

usage: rsc Uri [Options]

Non-option arguments:
[String: Uri]

Option                              Description
------                              -----------
--channel                           Shortcut of --im REQUEST_CHANNEL
-d, --data [String]                 Data. Use '-' to read data from

...

請保持此終端視窗開啟,稍後會用到。

步驟 2:檢查伺服器程式碼

在你的 IDE 中開啟 rsocket-server 專案並檢查程式碼。如你所見,在 Spring Boot 中啟動 RSocket 伺服器所需的程式碼量非常少。以下是一些亮點:

專案檔案

在專案的 pom.xml 檔案中,你可以看到 Spring Boot RSocket 伺服器所需的 <dependencies>。使用的是 Spring Boot 2.2.5.RELEASE 版本,因為在撰寫本文時,此版本具有最成熟的 RSocket 功能。該專案還依賴於 lombokspring-boot-starter-rsocket 庫。Lombok 為 Java 資料類添加了建構函式、getter、setter 和 equals 方法,並簡化了對日誌等內容的訪問。RSocket 的 Spring Boot Starter 將 RSocket 與 Spring Boot 整合,並自動為你配置一些 RSocket 基礎設施。

應用程式屬性

application.properties 檔案中,RSocket 伺服器的 TCP 埠設定為 7000,並且 Spring Boot 的延遲初始化功能已開啟。

spring.rsocket.server.port=7000
spring.main.lazy-initialization=true

訊息類

第一個需要仔細檢視的類名為 Message.java。這個 Lombok @Data 類用於建模客戶端和伺服器(或者如果你願意,可以稱之為“請求者”和“響應者”)之間的請求和響應訊息。該類如下所示:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Message {
    private String origin;
    private String interaction;
    private long index;
    private long created = Instant.now().getEpochSecond();

    public Message(String origin, String interaction) {
        this.origin = origin;
        this.interaction = interaction;
        this.index = 0;
    }

    public Message(String origin, String interaction, long index) {
        this.origin = origin;
        this.interaction = interaction;
        this.index = index;
    }
}

使用此類別,你可以說明訊息的來源 (origin)、預期的訊息樣式 (interaction) 以及訊息序列中的序號 (index)。Lombok 透過提供建構函式、getter、setter、toString 和 hashcode 實現來簡化程式碼。

控制器類

RSocket 伺服器控制器程式碼可以在 RSocketController.java 檔案中找到。該類被註解為 Spring @Controller,這基本上意味著它聲明瞭服務端點——在本例中是 RSocket 端點。

@Controller
public class RSocketController {

    @MessageMapping("request-response")
    Message requestResponse(Message request) {
            log.info("Received request-response request: {}", request);
            // create a single Message and return it
            return new Message(SERVER, RESPONSE);
    }
}

在該類中,有一個名為 requestResponse() 的方法,它接受一個 Message 物件(請求)並返回一個 Message 物件(響應)。

你會注意到這個 requestResponse() 方法帶有 @MessageMapping("request-response") 註解。這個註解聲明瞭任何包含 RSocket 路由 request-response 元資料的訊息都應該由這個方法處理。你將在稍後從客戶端傳送請求訊息時使用這個路由。

你是否注意到這與 Spring 的 REST 控制器略有不同?對於 REST 控制器,URL 路徑對映(如 /hello)用於將 HTTP 呼叫與其處理方法關聯起來。

程式碼部分就到這裡。我們來試試看。

步驟 3:啟動 Spring Boot RSocket 伺服器

保持現有終端視窗開啟,在第二個終端視窗中,將 rsocket-server 資料夾設定為當前目錄。然後使用以下命令構建並執行 RSocket 伺服器:

./mvnw clean package spring-boot:run -DskipTests=true

或者,如果你願意,也可以使用 Java IDE 中的“構建”和“執行”命令。

步驟 4:使用 RSocket CLI 向伺服器傳送命令

接下來,你將使用在步驟 1 中下載並測試過的 RSocket 客戶端 rsc.jar 向正在執行的伺服器傳送訊息。回到你看到 --help 文字的原始終端視窗,然後執行以下命令:

java -jar rsc.jar --debug --request --data "{\"origin\":\"Client\",\"interaction\":\"Request\"}" --route request-response tcp://:7000

你會注意到該命令聲明瞭一個 RSocket 訊息路由(透過新增 --route 選項並指定路由名稱實現)。在這種情況下,路由是 request-response,它與 RSocketController.java 中請求-響應處理方法中宣告的 @MessageMapping 匹配。

命令執行時,你會在終端視窗中看到一些除錯資訊,解釋請求-響應互動過程中發生的情況。它看起來像這樣:

2020-02-27 11:20:21.806 DEBUG --- [actor-tcp-nio-1] i.r.FrameLogger : sending ->
Frame => Stream ID: 1 Type: REQUEST_RESPONSE Flags: 0b100000000 Length: 69
Metadata:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 10 72 65 71 75 65 73 74 2d 72 65 73 70 6f 6e 73 |.request-respons|
|00000010| 65                                              |e               |
+--------+-------------------------------------------------+----------------+
Data:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 6f 72 69 67 69 6e 22 3a 22 43 6c 69 65 6e |{"origin":"Clien|
|00000010| 74 22 2c 22 69 6e 74 65 72 61 63 74 69 6f 6e 22 |t","interaction"|
|00000020| 3a 22 52 65 71 75 65 73 74 22 7d                |:"Request"}     |
+--------+-------------------------------------------------+----------------+
2020-02-27 11:20:21.927 DEBUG --- [actor-tcp-nio-1] i.r.FrameLogger : receiving ->
Frame => Stream ID: 1 Type: NEXT_COMPLETE Flags: 0b1100000 Length: 81
Data:
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 7b 22 6f 72 69 67 69 6e 22 3a 22 53 65 72 76 65 |{"origin":"Serve|
|00000010| 72 22 2c 22 69 6e 74 65 72 61 63 74 69 6f 6e 22 |r","interaction"|
|00000020| 3a 22 52 65 73 70 6f 6e 73 65 22 2c 22 69 6e 64 |:"Response","ind|
|00000030| 65 78 22 3a 30 2c 22 63 72 65 61 74 65 64 22 3a |ex":0,"created":|
|00000040| 31 35 38 32 38 30 32 34 32 31 7d                |1582802421}     |
+--------+-------------------------------------------------+----------------+
{"origin":"Server","interaction":"Response","index":0,"created":1582802421}

你看到的除錯輸出分為三個“訊息幀”。第一個訊息幀標記為 Metadata。在這種情況下,它顯示了傳送到伺服器的路由元資料 (request-response)。第二個幀顯示客戶端傳送到伺服器的 Data 訊息(一個 JSON 字串)。第三個幀顯示伺服器返回給客戶端的響應訊息(也是一個 JSON 字串)。

在最後一行,你可以看到伺服器以 JSON 格式獨立列印的響應,這證實了我們的命令訊息已成功被伺服器接收並確認。

{"origin":"Server","interaction":"Response","index":0,"created":1582802421}

恭喜你!你完成了。你剛剛使用 RSocket 傳送了一個請求-響應訊息。現在你可以透過在終端視窗中按 Ctrl-C 或關閉它來停止 RSocket 伺服器。如果你使用 IDE 執行 RSocket 伺服器,你可以像往常一樣在 IDE 中停止程序。

工作原理

你下載的 RSocket rsc 客戶端使用 RSocket 訊息協議向 RSocketController 傳送請求訊息。訊息透過 TCP 傳送到地址 tcp://:7000,伺服器正在該地址等待。

第一條訊息幀中傳送了訊息路由指令。此路由指令使用 CLI 客戶端的 --route 選項設定,並設定為 request-response。Spring 使用此路由資訊選擇要呼叫的正確 @MessageMapping 端點,在本例中是 requestResponse(Message request) 方法。該方法隨後響應自己的訊息。CLI 客戶端將整個互動作為一系列訊息幀列印在終端視窗中。

總結

如果你按照步驟操作,你會發現使用 Spring Boot 編寫一個簡單的 RSocket 伺服器是多麼容易。你檢查了所需的 Java 程式碼,然後在本地啟動了 Spring Boot 伺服器。然後你向 RSocket 伺服器傳送了一條訊息並觀察了響應。你還學習瞭如何使用 RSocket 訊息路由功能在 Spring 中路由 RSocket 訊息。在下一篇文章中,你將學習如何開始使用 Spring Boot 構建自己的 RSocket 客戶端

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有