Spring Boot 的服务器端事件消费者

问题描述 投票:0回答:1

鉴于我有这个 service-A ,此端点返回 contentType(MediaType.TEXT_EVENT_STREAM)

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

我需要从另一个 Spring Boot service-B 中使用它,它当前使用 RestTemplate (它还没有响应)。

  1. 问题 1-> 可以使用restTemplate 来完成此操作,并以某种方式使用 SseEmitter(流式传输到 UI)类来流式传输来自 service-A 的事件。
  2. 问题 2 -> 鉴于此 service-B 是一个普通的 MVC,具有 Spring Security 集成。我也可以带上 webflux 并且两者都可以工作吗?
  3. 问题 3 -> 对于该场景是否还有其他潜在的解决方案。

即使我带了 spring webflux,我也会得到一些安全过滤器链重复的 beans。

spring-boot spring-webflux project-reactor reactive spring-resttemplate
1个回答
0
投票

问题 1-> 可以使用restTemplate 来完成此操作,并以某种方式使用 SseEmitter(流式传输到 UI)类来流式传输来自服务 A 的事件。

问题 1:是的,可以使用 RestTemplate 使用来自服务 A 的 SSE(服务器发送事件)流,但这不是最有效的方法。 RestTemplate是同步、阻塞的,而SSE是异步、非阻塞的协议。但是,您仍然可以使用 RestTemplate 和解决方法来处理 SSE。您需要创建一个单独的线程来连续读取 SSE 流并处理事件。 SseEmitter 不直接与 RestTemplate 兼容,因为它是 Spring WebFlux 的一部分,而 Spring WebFlux 是为响应式编程而设计的。

鉴于此service-B是一个普通的MVC,具有Spring Security集成。我也可以带上 webflux 并且两者都可以工作吗?

问题 2:是的,您可以将 Spring WebFlux 与 Spring MVC 一起引入 Spring Security 集成。 Spring WebFlux 旨在与 Spring MVC 无缝协作,允许您逐步迁移到响应式架构。您可以在同一个应用程序中同时使用两者。

对于这种情况还有其他潜在的解决方案吗?

问题 3:您的场景的潜在解决方案包括:

a.使用 WebClient(响应式方法):您可以使用 Spring WebFlux 中的 WebClient,而不是 RestTemplate,它是非阻塞且响应式的。它更适合使用 SSE 等反应式流。

b.代理服务:创建一个单独的 Spring WebFlux 服务,该服务使用来自服务 A 的 SSE 流并公开 REST API。然后,您的 Spring MVC 服务 B 可以使用 RestTemplate 使用此 REST API。

非阻塞-反应式-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>

SERVET 阻止模型 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 之外,你还可以像下面这样编写代码来启动不同的 Web 服务容器。

 SpringApplication app = new SpringApplication(Application.class);
        app.setWebApplicationType(WebApplicationType.SERVLET);
        app.run(args);
public enum WebApplicationType {
    NONE,
    SERVLET,
    REACTIVE;
}
© www.soinside.com 2019 - 2024. All rights reserved.