Учитывая, что у меня есть эта служба-A с этой конечной точкой, которая возвращает contentType(MediaType.TEXT_EVENT_STREAM)
@Bean
public RouterFunction<ServerResponse> notificationsRoute(CustomHandler someCustomHandler) {
return route()
.GET("/orders", someCustomHandler:handle)
.build();
}
Мне нужно использовать это из другой службы весенней загрузки-B, которая в настоящее время использует restTemplate (она еще не реактивна).
Даже если я принесу Spring Webflux, я получаю дублирующиеся компоненты цепочки фильтров безопасности.
спасибо @amanin за ваш ответ. Но если я сделаю это «spring.main.web-application-type: servlet», тогда, когда я вызову эту конечную точку, которая описана как маршрут, я получу 404, что означает, что тогда Spring Boot не раскрывает эту конечную точку, а это не то, что я хочу... Я посмотрю RestClient, чтобы узнать, допускает ли последняя реализация какие-либо события на стороне сервера.
Вопрос 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.
@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>
@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 Я решил использовать прокси-сервис с использованием веб-клиента для потоковой передачи событий клиентам, немного больше работы заранее, но оно того стоит.
В пути к классам могут быть как MVC, так и Webflux. Однако вам, возможно, придется явно определить
spring.main.web-application-type: servlet
в своих свойствах, иначе у Spring могут возникнуть проблемы с пониманием, должен ли он запускать сервер MVC или Webflux. Но добавление webflux должно позволить вам использовать реактивWebClient
. В противном случае я не знаю, достижимо ли это с помощью RestTemplate. Возможно, новый нереактивный RestClient имеет возможности потоковой передачи, но я еще не тестировал его.