Spring Web Reactive | 5. RSocket | 5.3. Annotated Responders

Implement RSocket responders with @MessageMapping and @ConnectMapping methods. @MessageMapping handles individual requests. @ConnectMapping handles connection-level events such as setup and metadata push. Annotated responders are supported symmetrically for server-side and client-side responses.

5.3.1. Server Responders

Add RSocketMessageHandler to the Spring configuration to discover @Controller Beans with @MessageMapping and @ConnectMapping methods.

@Configuration
class ServerConfig {
    @Bean
    fun rsocketMessageHandler() = RSocketMessageHandler().apply {
        routeMatcher = PathPatternRouteMatcher()
    }
}

Start an RSocket server and connect the responder:

val context: ApplicationContext = ...
val handler = context.getBean<RSocketMessageHandler>()

val server = RSocketServer.create(handler.responder())
        .bind(TcpServerTransport.create("localhost", 7000))
        .awaitSingle()

RSocketMessageHandler supports composite metadata and routing metadata by default. Configure MetadataExtractor for other MIME types. Configure required encoder and decoder instances for supported metadata and data formats.

By default, SimpleRouteMatcher uses AntPathMatcher. For efficient route matching, use PathPatternRouteMatcher from spring-web. RSocket routes can be hierarchical but are not URL paths. Route matchers use . as the separator by default and do not perform URL decoding.

You can configure RSocketMessageHandler with shared RSocketStrategies.

RSocketStrategies.builder()
    .encoders(encoders -> encoders.add(new Jackson2CborEncoder()))
    .decoders(decoders -> decoders.add(new Jackson2CborDecoder()))
    .routeMatcher(new PathPatternRouteMatcher())
    .build();

5.3.2. Client Responders

Configure client-side annotated responders with RSocketRequester.Builder. See client responders.

5.3.3. @MessageMapping

After configuring server or client responders, use @MessageMapping methods:

@Controller
public class RadarsController {
    @MessageMapping("locate.radars.within")
    public Flux<AirportLocation> radars(MapRequest request) {
        // ...
    }
}

The method responds to a Request-Stream interaction with the route locate.radars.within.

Method argument Description
@Payload Request payload. The annotation is optional when the argument is not another supported argument type.
RSocketRequester Requester for calling the remote endpoint.
@DestinationVariable Value extracted from a route variable such as @MessageMapping("find.radar.{id}").
@Header Metadata value registered for extraction by MetadataExtractor.
@Headers Map<String, Object> All metadata values registered for extraction.

Return values are serialized as response payloads. They can be concrete values, asynchronous types such as Mono and Flux, or no-value types such as void and Mono<Void>.

Input cardinality Output cardinality Interaction type
0, 1 0 Fire-and-Forget
0, 1 1 Request-Response
0, 1 Many Request-Stream
Many 0, 1, Many Request-Channel

5.3.4. @ConnectMapping

@ConnectMapping handles the SETUP frame when an RSocket connection begins and subsequent metadata push notifications through METADATA_PUSH.

It supports the same arguments as @MessageMapping, based on metadata and data from SETUP and METADATA_PUSH frames. A route pattern can narrow the connections to handle; without a pattern, all connections match.

@ConnectMapping methods cannot return data. Declare a void or Mono<Void> return type. If handling a new connection returns an error, the connection is rejected.