RSocket
RSocket 是一種用於位元組流傳輸的二進位制協議。它透過單個連線上的非同步訊息傳遞實現了對稱的互動模型。
Spring Framework 的 spring-messaging
模組提供了對 RSocket 請求者(requesters)和響應者(responders)的支援,包括客戶端和伺服器端。有關更多詳細資訊,包括 RSocket 協議的概覽,請參閱 Spring Framework 參考文件的RSocket 部分。
RSocket Strategies 自動配置
Spring Boot 自動配置了一個 RSocketStrategies
bean,它提供了編碼和解碼 RSocket 有效負載所需的所有基礎設施。預設情況下,自動配置將嘗試按以下順序配置:
-
使用 Jackson 的 CBOR 編解碼器
-
使用 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
)
}
}