RSocket-респондери можуть бути реалізовані у вигляді методів з анотаціями @MessageMapping та @ConnectMapping. Методи, анотовані @MessageMapping, обробляють окремі запити, а методи, анотовані @ConnectMapping, — події на рівні з'єднання (встановлення та проштовхування метаданих). Анотовані респондери підтримуються симетрично, і для відповідей з боку сервера, і для відповідей з боку клієнта.

Респондери на стороні сервера

Щоб використовувати анотовані респондери на стороні сервера, додай RSocketMessageHandler до конфігурації Spring для виявлення позначених анотацією @Controller бінів з методами, анотованими @MessageMapping та @ConnectMapping:

Java
@Configuration
static class ServerConfig {
@Bean
public RSocketMessageHandler rsocketMessageHandler() {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.routeMatcher(new PathPatternRouteMatcher());
return handler;
}
}
Kotlin
@Configuration
class ServerConfig {
@Bean
fun rsocketMessageHandler() = RSocketMessageHandler().apply {
routeMatcher = PathPatternRouteMatcher()
}
}

Запусти RSocket-сервер через API RSocket для Java і підключи RSocketMessageHandler для респондера таким чином:

Java
ApplicationContext context = ... ;
RSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);
CloseableChannel server =
RSocketServer.create(handler.responder())
.bind(TcpServerTransport.create("localhost", 7000))
.block();
Kotlin
import org.springframework.beans.factory.getBean
val context: ApplicationContext = ...
val handler = context.getBean<RSocketMessageHandler>()
val server = RSocketServer.create(handler.responder())
.bind(TcpServerTransport.create("localhost", 7000))
.awaitSingle()

RSocketMessageHandler за замовчуванням підтримує складені метадані та метадані маршрутизації. Можна налаштувати його MetadataExtractor, якщо потрібно переключитися на інший MIME-тип або зареєструвати додаткові MIME-типи метаданих.

Необхідно буде налаштувати екземпляри Encoder та Decoder, які потрібні для підтримки метаданих та форматів даних. Для реалізації кодеків, швидше за все, знадобиться модуль spring-web.

За замовчуванням SimpleRouteMatcher використовується для узгодження маршрутів через AntPathMatcher. Рекомендуємо підключити PathPatternRouteMatcher зі spring-web для ефективного узгодження маршрутів. Маршрути RSocket можуть бути ієрархічними, але не є URL-шляхами. Обидва засоби зіставлення маршрутів налаштовані на використання "." як роздільника за замовчуванням, а декодування URL-адрес, як у випадку з URL-адресами HTTP, відсутнє.

RSocketMessageHandler можна налаштувати через RSocketStrategies, що може бути корисно, якщо необхідно розділити конфігурацію між клієнтом і сервером в тому самому процесі:

Java
@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();
}
}
Kotlin

@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()
}

Респондери на стороні клієнта

Анотовані респондери на стороні клієнта повинні бути налаштовані в RSocketRequester.Builder.

@MessageMapping

Після того, як конфігурація респондера для server або client буде налаштована, методи з анотацією @MessageMapping можна буде використовувати таким чином:

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

Наведений вище метод, позначений анотацією @MessageMapping, реагує на взаємодію типу Request-Stream з маршрутом "locate.radars.within". Він підтримує гнучку сигнатуру методу з можливістю використання наступних аргументів методу:

Аргумент методу Опис

@Payload

Корисні дані запиту. Це може бути конкретне значення асинхронних типів, як-от Mono або Flux.

Примітка: використання анотації не є обов'язковим. Аргумент методу, який не є ані простим типом, ані одним із інших аргументів, що підтримуються, приймається за очікувані корисні дані.

RSocketRequester

Реквестер для передачі запитів приймальній стороні.

@DestinationVariable

Значення, витягнуте з маршруту на основі змінних у шаблоні відображення, наприклад @MessageMapping("find.radar.{id}").

@Header

Значення метаданих, зареєстроване для вилучення.

@Headers Map<String, Object>

Всі значення метаданих, зареєстровані для вилучення.

Очікується, що значенням, що повертається, буде один або кілька об'єктів, які будуть серіалізовані в якості корисних даних відповіді. Це можуть бути асинхронні типи, такі як Mono або Flux, конкретне значення, або void або асинхронний тип без значення, такий як Mono<Void>.

Тип взаємодії RSocket, який підтримує метод, анотований @MessageMapping, визначається за потужністю множини введення (тобто аргументу, анотованого @Payload) і виведення, де потужність множини означає наступне:

Потужність множини Опис

1

Або явне значення, або асинхронний тип з одним значенням, такий як Mono<T>.

Many

Многозначний асинхронний тип, такий як Flux<T>.

0

У разі введення це означає, що метод не має аргументу, анотованого @Payload.

У випадку виведення це void або асинхронний тип, що не має значення, такий як Mono<Void>.

У таблиці нижче представлені всі комбінації потужності множини введення та виведення та відповідний тип(и) взаємодії:

Потужність множини введення Потужність множини виведення Типи взаємодії

0, 1

0

Fire-and-Forget, Request-Response

0, 1

1

Request-Response

0, 1

Багато

Request-Stream

Багато

0, 1, безліч

Request-Channel

@ConnectMapping

Анотація @ConnectMapping обробляє кадр SETUP на початку встановлення RSocket-з'єднання і всі наступні повідомлення про проштовхування метаданих через кадр METADATA_PUSH, тобто metadataPush(Payload) у io.rsocket.RSocket.

Методи з анотацією @ConnectMapping підтримують ті самі аргументи, що і методи з анотацією @MessageMapping, але засновані на метаданих та даних з кадрів SETUP і METADATA_PUSH. Анотація @ConnectMapping може бути забезпечена шаблоном для відмежування процедури обробки певними сполуками, які мають маршрут у метаданих, а якщо шаблони не будуть оголошені, всі з'єднання будуть відповідати.

Методи, анотовані @ConnectMapping, не можуть повертати дані, тому їх потрібно оголошувати з використанням void або Mono<Void> як значення, що повертається. Якщо процедура обробки повертає помилку для нового з'єднання, з'єднання відхиляється. Процедура обробки не повинна затягуватися, щоб можна було виконати запити до RSocketRequester для конкретного з'єднання.