JavaRush /Курси /Модуль 5. Spring /Анотовані респондери

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

Модуль 5. Spring
Рівень 14 , Лекція 7
Відкрита

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 для конкретного з'єднання.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ