Annotated Responders
RSocket responders can be implemented as @MessageMapping
and @ConnectMapping
methods.
@MessageMapping
methods handle individual requests while @ConnectMapping
methods handle
connection-level events (setup and metadata push). Annotated responders are supported
symmetrically, for responding from the server side and for responding from the client side.
Server Responders
To use annotated responders on the server side, add RSocketMessageHandler
to your Spring
configuration to detect @Controller
beans with @MessageMapping
and @ConnectMapping
methods:
@Configuration
static class ServerConfig {
@Bean
public RSocketMessageHandler rsocketMessageHandler() {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.routeMatcher(new PathPatternRouteMatcher());
return handler;
}
}
@Configuration
class ServerConfig {
@Bean
fun rsocketMessageHandler() = RSocketMessageHandler().apply {
routeMatcher = PathPatternRouteMatcher()
}
}
Then start an RSocket server through the Java RSocket API and plug the
RSocketMessageHandler
for the responder as follows:
ApplicationContext context = ... ;
RSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);
CloseableChannel server =
RSocketFactory.receive()
.acceptor(handler.responder())
.transport(TcpServerTransport.create("localhost", 7000))
.start()
.block();
import org.springframework.beans.factory.getBean
val context: ApplicationContext = ...
val handler = context.getBean<RSocketMessageHandler>()
val server = RSocketFactory.receive()
.acceptor(handler.responder())
.transport(TcpServerTransport.create("localhost", 7000))
.start().awaitFirst()
RSocketMessageHandler
supports
composite and
routing metadata by default. You can set its
rsocket-metadata-extractor if you need to switch to a
different mime type or register additional metadata mime types.
You’ll need to set the Encoder
and Decoder
instances required for metadata and data
formats to support. You’ll likely need the spring-web
module for codec implementations.
By default SimpleRouteMatcher
is used for matching routes via AntPathMatcher
.
We recommend plugging in the PathPatternRouteMatcher
from spring-web
for
efficient route matching. RSocket routes can be hierarchical but are not URL paths.
Both route matchers are configured to use "." as separator by default and there is no URL
decoding as with HTTP URLs.
RSocketMessageHandler
can be configured via RSocketStrategies
which may be useful if
you need to share configuration between a client and a server in the same process:
@Configuration
static class ServerConfig {
@Bean
public RSocketMessageHandler rsocketMessageHandler() {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.setRSocketStrategies(rsocketStrategies());
return handler;
}
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoders(encoders -> encoders.add(new Jackson2CborEncoder))
.decoders(decoders -> decoders.add(new Jackson2CborDecoder))
.routeMatcher(new PathPatternRouteMatcher())
.build();
}
}
@Configuration
class ServerConfig {
@Bean
fun rsocketMessageHandler() = RSocketMessageHandler().apply {
rSocketStrategies = rsocketStrategies()
}
@Bean
fun rsocketStrategies() = RSocketStrategies.builder()
.encoders { it.add(Jackson2CborEncoder()) }
.decoders { it.add(Jackson2CborDecoder()) }
.routeMatcher(PathPatternRouteMatcher())
.build()
}
Client Responders
Annotated responders on the client side need to be configured in the
RSocketRequester.Builder
. For details, see
rsocket-requester-client-responder.
@MessageMapping
Once server or
client responder configuration is in place,
@MessageMapping
methods can be used as follows:
@Controller
public class RadarsController {
@MessageMapping("locate.radars.within")
public Flux<AirportLocation> radars(MapRequest request) {
// ...
}
}
@Controller
class RadarsController {
@MessageMapping("locate.radars.within")
fun radars(request: MapRequest): Flow<AirportLocation> {
// ...
}
}
The above @MessageMapping
method responds to a Request-Stream interaction having the
route "locate.radars.within". It supports a flexible method signature with the option to
use the following method arguments:
Method Argument | Description |
---|---|
|
The payload of the request. This can be a concrete value of asynchronous types like
Note: Use of the annotation is optional. A method argument that is not a simple type and is not any of the other supported arguments, is assumed to be the expected payload. |
|
Requester for making requests to the remote end. |
|
Value extracted from the route based on variables in the mapping pattern, e.g.
|
|
Metadata value registered for extraction as described in rsocket-metadata-extractor. |
|
All metadata values registered for extraction as described in rsocket-metadata-extractor. |
The return value is expected to be one or more Objects to be serialized as response
payloads. That can be asynchronous types like Mono
or Flux
, a concrete value, or
either void
or a no-value asynchronous type such as Mono<Void>
.
The RSocket interaction type that an @MessageMapping
method supports is determined from
the cardinality of the input (i.e. @Payload
argument) and of the output, where
cardinality means the following:
Cardinality | Description |
---|---|
1 |
Either an explicit value, or a single-value asynchronous type such as |
Many |
A multi-value asynchronous type such as |
0 |
For input this means the method does not have an For output this is |
The table below shows all input and output cardinality combinations and the corresponding interaction type(s):
Input Cardinality | Output Cardinality | Interaction Types |
---|---|---|
0, 1 |
0 |
Fire-and-Forget, Request-Response |
0, 1 |
1 |
Request-Response |
0, 1 |
Many |
Request-Stream |
Many |
0, 1, Many |
Request-Channel |
@ConnectMapping
@ConnectMapping
handles the SETUP
frame at the start of an RSocket connection, and
any subsequent metadata push notifications through the METADATA_PUSH
frame, i.e.
metadataPush(Payload)
in io.rsocket.RSocket
.
@ConnectMapping
methods support the same arguments as
rsocket-annot-messagemapping but based on metadata and data from the SETUP
and
METADATA_PUSH
frames. @ConnectMapping
can have a pattern to narrow handling to
specific connections that have a route in the metadata, or if no patterns are declared
then all connections match.
@ConnectMapping
methods cannot return data and must be declared with void
or
Mono<Void>
as the return value. If handling returns an error for a new
connection then the connection is rejected. Handling must not be held up to make
requests to the RSocketRequester
for the connection. See
rsocket-requester-server for details.