RSocket

RSocket 是一種用於位元組流傳輸的二進位制協議。它透過單個連線上的非同步訊息傳遞實現了對稱的互動模型。

Spring Framework 的 spring-messaging 模組提供了對 RSocket 請求者(requesters)和響應者(responders)的支援,包括客戶端和伺服器端。有關更多詳細資訊,包括 RSocket 協議的概覽,請參閱 Spring Framework 參考文件的RSocket 部分

RSocket Strategies 自動配置

Spring Boot 自動配置了一個 RSocketStrategies bean,它提供了編碼和解碼 RSocket 有效負載所需的所有基礎設施。預設情況下,自動配置將嘗試按以下順序配置:

  1. 使用 Jackson 的 CBOR 編解碼器

  2. 使用 Jackson 的 JSON 編解碼器

spring-boot-starter-rsocket starter 同時提供了這兩個依賴。有關定製可能性的更多資訊,請參閱Jackson 支援部分

開發者可以透過建立實現 RSocketStrategiesCustomizer 介面的 bean 來定製 RSocketStrategies 元件。請注意,它們的 @Order 很重要,因為它決定了編解碼器的順序。

RSocket 伺服器自動配置

Spring Boot 提供了 RSocket 伺服器自動配置。所需的依賴由 spring-boot-starter-rsocket 提供。

Spring Boot 允許從 WebFlux 伺服器透過 WebSocket 暴露 RSocket,或者啟動一個獨立的 RSocket 伺服器。這取決於應用的型別及其配置。

對於 WebFlux 應用(即型別為 WebApplicationType.REACTIVE 的應用),只有當以下屬性匹配時,RSocket 伺服器才會被整合到 Web 伺服器中:

  • 屬性

  • YAML

spring.rsocket.server.mapping-path=/rsocket
spring.rsocket.server.transport=websocket
spring:
  rsocket:
    server:
      mapping-path: "/rsocket"
      transport: "websocket"
將 RSocket 整合到 Web 伺服器只支援 Reactor Netty,因為 RSocket 本身就是基於該庫構建的。

另外,可以將 RSocket TCP 或 WebSocket 伺服器作為獨立的嵌入式伺服器啟動。除了依賴要求外,唯一必要的配置是為該伺服器定義一個埠:

  • 屬性

  • YAML

spring.rsocket.server.port=9898
spring:
  rsocket:
    server:
      port: 9898

Spring Messaging RSocket 支援

Spring Boot 將自動配置用於 RSocket 的 Spring Messaging 基礎設施。

這意味著 Spring Boot 將建立一個 RSocketMessageHandler bean,該 bean 將處理傳送到你的應用的 RSocket 請求。

使用 RSocketRequester 呼叫 RSocket 服務

一旦在伺服器和客戶端之間建立了 RSocket 通道,任何一方都可以向另一方傳送或接收請求。

作為伺服器,你可以在 RSocket @Controller 的任何處理方法中注入一個 RSocketRequester 例項。作為客戶端,你需要先配置並建立 RSocket 連線。Spring Boot 為這種情況自動配置了一個 RSocketRequester.Builder,其中包含預期的編解碼器,並應用任何 RSocketConnectorConfigurer bean。

RSocketRequester.Builder 例項是一個原型(prototype)bean,這意味著每個注入點都將為你提供一個新例項。這是故意設計的,因為這個 builder 是有狀態的,你不應該使用同一個例項來建立具有不同設定的請求者。

以下程式碼顯示了一個典型示例:

  • Java

  • Kotlin

import reactor.core.publisher.Mono;

import org.springframework.messaging.rsocket.RSocketRequester;
import org.springframework.stereotype.Service;

@Service
public class MyService {

	private final RSocketRequester rsocketRequester;

	public MyService(RSocketRequester.Builder rsocketRequesterBuilder) {
		this.rsocketRequester = rsocketRequesterBuilder.tcp("example.org", 9898);
	}

	public Mono<User> someRSocketCall(String name) {
		return this.rsocketRequester.route("user").data(name).retrieveMono(User.class);
	}

}
import org.springframework.messaging.rsocket.RSocketRequester
import org.springframework.stereotype.Service
import reactor.core.publisher.Mono

@Service
class MyService(rsocketRequesterBuilder: RSocketRequester.Builder) {

	private val rsocketRequester: RSocketRequester

	init {
		rsocketRequester = rsocketRequesterBuilder.tcp("example.org", 9898)
	}

	fun someRSocketCall(name: String): Mono<User> {
		return rsocketRequester.route("user").data(name).retrieveMono(
			User::class.java
		)
	}

}