Spring Web Reactive | 5. RSocket | 5.1. Overview

RSocket is an application protocol for multiplexed, duplex communication over TCP, WebSocket, and other byte-stream transports. It uses one of the following interaction models:

  • Request-Response: Send one message and receive one.
  • Request-Stream: Send one message and receive a stream of messages.
  • Channel: Send streams of messages in both directions.
  • Fire-and-Forget: Send a one-way message.

After the initial connection is established, both sides are symmetrical and either side can initiate an interaction. The distinction between client and server disappears. Participants are therefore called requesters and responders, and the interactions are called request streams or simply requests.

Key RSocket features and benefits include:

  • Reactive Streams semantics across network boundaries: Backpressure signals travel between requester and responder for streaming requests such as Request-Stream and Channel. This lets requests slow the responder at the source and reduces reliance on network-layer congestion control and buffering.
  • Request throttling: This feature is called leasing after the LEASE frame. Each endpoint can limit how many requests the other endpoint may send during a given period. Leases are updated periodically.
  • Session resumption: Some state can be retained after a connection is lost. State management is transparent to the application and works with backpressure to stop producers when possible and reduce the required state.
  • Fragmentation and reassembly of large messages.
  • Keepalive heartbeats.

RSocket has implementations in multiple languages. The Java library is built on Project Reactor and uses Reactor Netty for transport. Signals from application Reactive Streams publishers are carried transparently across the network through RSocket.

5.1.1. Protocol

One benefit of RSocket is its readable specification, which defines network behavior and protocol extensions. Reading the specification is useful regardless of language implementation or higher-level framework APIs. This section provides a concise overview.

Connecting

A client first connects to a server through a lower-level streaming transport such as TCP or WebSocket. It sends a SETUP frame to establish connection parameters.

The server can reject the SETUP frame. Normally, after sending and receiving it, either side can start requests unless SETUP uses leasing semantics to limit them. In that case, each side must wait for a LEASE frame from the other side.

Making Requests

After connecting, either side can initiate a request with a REQUEST_RESPONSE, REQUEST_STREAM, REQUEST_CHANNEL, or REQUEST_FNF frame. Each frame carries one message from requester to responder.

The responder returns PAYLOAD frames containing response messages. With REQUEST_CHANNEL, the requester also sends PAYLOAD frames containing additional request messages.

For message streams such as Request-Stream and Channel, the responder must respect demand signals from the requester. Demand is expressed as a number of messages. Initial demand is specified in REQUEST_STREAM and REQUEST_CHANNEL frames. Subsequent demand is signaled through REQUEST_N frames.

Either side can also send metadata notifications for the entire connection, rather than an individual request, through METADATA_PUSH frames.

Message Format

RSocket messages contain data and metadata. Metadata can carry routes, security tokens, and other values. Data and metadata can use different formats. Their MIME types are declared in the SETUP frame and apply to every request on the connection.

Metadata can be included in every message, but request-level metadata such as a route is usually included only in the first message: a REQUEST_RESPONSE, REQUEST_STREAM, REQUEST_CHANNEL, or REQUEST_FNF frame.

Protocol extensions define common metadata formats:

5.1.2. Java Implementation

The RSocket Java implementation is built on Project Reactor. TCP and WebSocket transports use Reactor Netty. Reactor simplifies protocol implementation, and applications naturally use Flux and Mono with declarative operators and transparent backpressure support.

The RSocket Java API is intentionally minimal. It focuses on protocol features and treats application programming models, such as RPC code generation, as independent higher-level concerns.

The primary io.rsocket.RSocket contract models the four request interaction types using Mono for one message, Flux for message streams, and io.rsocket.Payload for messages that expose data and metadata as byte buffers. The contract is symmetrical: applications receive an RSocket to make requests and implement an RSocket to handle responses.

This is not a complete introduction. Spring applications usually do not need to use the API directly, but experimenting with RSocket without Spring can be useful. The RSocket Java repository contains many sample applications.

5.1.3. Spring Support

The spring-messaging module includes:

  • RSocketRequester: A fluent API for making requests through io.rsocket.RSocket with data and metadata encoding and decoding.
  • Annotated responders: Annotated handler methods for @MessageMapping responses.

The spring-web module includes encoder and decoder implementations such as Jackson CBOR/JSON and Protobuf, which RSocket applications are likely to need. It also includes a pluggable PathPatternParser for efficient route matching.

Spring Boot 2.2 supports launching RSocket servers over TCP or WebSocket, including publishing RSocket over WebSocket from a WebFlux server. It also provides client support and auto-configuration for RSocketRequester.Builder and RSocketStrategies. See the Spring Boot reference RSocket section.

Spring Security 5.2 provides RSocket support.

Spring Integration 5.2 provides inbound and outbound gateways for interacting with RSocket clients and servers. See the Spring Integration reference documentation for details.

Spring Cloud Gateway supports RSocket connections.