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. Java SDK 版本 8 或更高(要檢查,請在終端中使用 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 的更容易使用一些。在終端中,按如下方式下載 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 控制器,使用/hello這樣的 URL 路徑對映將 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 伺服器傳送了一條訊息並觀察了響應。您還學習瞭如何在 Spring 中使用 RSocket 訊息路由功能來路由您的 RSocket 訊息。在下一篇文章中,您將學習如何使用 Spring Boot 開始構建您自己的 RSocket 客戶端

獲取 Spring 郵件列表

訂閱 Spring 郵件列表,保持聯絡

訂閱

領先一步

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

瞭解更多

獲取支援

Tanzu Spring 透過一個簡單的訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將舉辦的活動

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

檢視全部