Потребитель событий на стороне сервера из весенней загрузки

Учитывая, что у меня есть эта служба-A с этой конечной точкой, которая возвращает contentType(MediaType.TEXT_EVENT_STREAM)

@Bean
    public RouterFunction<ServerResponse> notificationsRoute(CustomHandler someCustomHandler) {
        return route()
                .GET("/orders", someCustomHandler:handle)
                .build();
    }

Мне нужно использовать это из другой службы весенней загрузки-B, которая в настоящее время использует restTemplate (она еще не реактивна).

  1. Вопрос 1-> можно ли это сделать с помощью restTemplate и каким-то образом класса SseEmitter (для потоковой передачи в пользовательский интерфейс) для потоковой передачи событий из службы-A.
  2. Вопрос 2 -> Учитывая, что этот сервис-B представляет собой обычный MVC с интеграцией безопасности Spring. Могу ли я также использовать Webflux, чтобы оба работали?
  3. Вопрос 3 -> есть ли какие-либо другие потенциальные решения для этого сценария.

Даже если я принесу Spring Webflux, я получаю дублирующиеся компоненты цепочки фильтров безопасности.

В пути к классам могут быть как MVC, так и Webflux. Однако вам, возможно, придется явно определить spring.main.web-application-type: servlet в своих свойствах, иначе у Spring могут возникнуть проблемы с пониманием, должен ли он запускать сервер MVC или Webflux. Но добавление webflux должно позволить вам использовать реактив WebClient. В противном случае я не знаю, достижимо ли это с помощью RestTemplate. Возможно, новый нереактивный RestClient имеет возможности потоковой передачи, но я еще не тестировал его.

amanin 02.05.2024 15:04

спасибо @amanin за ваш ответ. Но если я сделаю это «spring.main.web-application-type: servlet», тогда, когда я вызову эту конечную точку, которая описана как маршрут, я получу 404, что означает, что тогда Spring Boot не раскрывает эту конечную точку, а это не то, что я хочу... Я посмотрю RestClient, чтобы узнать, допускает ли последняя реализация какие-либо события на стороне сервера.

daniel 04.05.2024 20:27
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
1
2
306
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вопрос 1-> можно ли это сделать с помощью restTemplate и каким-то образом класса SseEmitter (для потоковой передачи в пользовательский интерфейс) для потоковой передачи событий из службы-A.

Вопрос 1: Да, можно использовать поток SSE (события, отправленные сервером) из службы A с помощью RestTemplate, но это не самый эффективный подход. RestTemplate является синхронным и блокирующим, а SSE — асинхронным и неблокирующим протоколом. Однако вы все равно можете использовать RestTemplate с обходным решением для обработки SSE. Вам потребуется создать отдельный поток для непрерывного чтения из потока SSE и обработки событий. SseEmitter не совместим напрямую с RestTemplate, поскольку является частью Spring WebFlux, предназначенного для реактивного программирования.

Учитывая, что этот сервис-B представляет собой обычный MVC с интеграцией безопасности Spring. Могу ли я также использовать Webflux, чтобы оба работали?

Вопрос 2: Да, вы можете использовать Spring WebFlux вместе со Spring MVC с интеграцией Spring Security. Spring WebFlux предназначен для бесперебойной работы с Spring MVC, что позволяет постепенно переходить к реактивной архитектуре. Вы можете использовать оба приложения вместе.

есть ли какие-либо другие потенциальные решения для этого сценария.

Вопрос 3. Возможные решения для вашего сценария включают:

а. Используйте WebClient (реактивный подход). Вместо RestTemplate вы можете использовать WebClient из Spring WebFlux, который является неблокирующим и реактивным. Он лучше подходит для потребления реактивных потоков, таких как SSE.

b.Прокси-сервис: создайте отдельный сервис Spring WebFlux, который использует поток SSE из сервиса-A и предоставляет REST API. Затем ваша служба Spring MVC-B может использовать этот REST API с помощью RestTemplate.

НЕБЛОКИРУЮЩИЙ - Реактивный -SSE



@RestController
public class SSEController {

    @GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> streamEvents() {
        return Flux.interval(Duration.ofSeconds(1))
                .map(sequence -> ServerSentEvent.<String>builder()
                        .id(String.valueOf(sequence))
                        .event("event")
                        .data("SSE Event #" + sequence + " at " + LocalTime.now())
                        .build());
    }
}

ЗАВИСИМОСТЬ

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

БЛОКИРОВОЧНАЯ МОДЕЛЬ SERLVET SSE


@RestController
public class SSEController {

    @GetMapping("/events")
    public SseEmitter streamEvents() {
        SseEmitter emitter = new SseEmitter();
        
        // Using a scheduled executor service to simulate periodic events
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleAtFixedRate(() -> {
            try {
                // Send event data
                emitter.send(SseEmitter.event().data("SSE Event at " + LocalTime.now()));
            } catch (IOException e) {
                // Log or handle the exception
            }
        }, 0, 1, TimeUnit.SECONDS);

        // Complete the emitter after a fixed delay
        executorService.schedule(() -> {
            emitter.complete();
            executorService.shutdown();
        }, 10, TimeUnit.SECONDS);

        return emitter;
    }
}

Помимо Spring.main.web-application-type: servlet, вы можете написать следующий код для запуска другого контейнера веб-сервиса.

 SpringApplication app = new SpringApplication(Application.class);
        app.setWebApplicationType(WebApplicationType.SERVLET);
        app.run(args);
public enum WebApplicationType {
    NONE,
    SERVLET,
    REACTIVE;
}

спасибо @Peng Я решил использовать прокси-сервис с использованием веб-клиента для потоковой передачи событий клиентам, немного больше работы заранее, но оно того стоит.

daniel 27.05.2024 17:36

Другие вопросы по теме

Похожие вопросы

Приложение имеет несколько экземпляров. Существует задание, которое будет выполняться в определенное время. как я могу заставить задание выполняться только одним экземпляром?
Как получить ответ на вызов API с помощью шаблона Rest, когда тип ответа неизвестен
Spring загрузка аннотации @Async с @Scheduled
Spring Boot Concurrency/множественные запросы, вызывающие чередование/повреждение данных в таблице базы данных с состоянием
Сопоставьте сложные DTO с Entity через Mapstruct
Очистка базы данных между тестами в тестовом контейнере Keycloak
Сохранение объекта с составным ключом JPA @ManyToOne, используемым в качестве идентификаторов, добавляет дополнительный параметр
Метод интерфейса, сгенерированный OpenApi, имеет возвращаемый тип как Object (Spring Boot 3)
Микрометр не работает при использовании в отдельных сервисах
Дубликат заголовка «Transfer-Encoding» в ответе вызывает исключение клиента — «java.io.IOException: недопустимый символ в размере фрагмента: 123»