Reaktive WebSockets mit Spring 5

Reaktive WebSockets mit Feder 5

1. Überblick

In diesem Artikel erstellen wir ein kurzes Beispiel mit der neuen Spring Framework 5 WebSockets-API sowie den reaktiven Funktionen des Spring WebFlux Framework.

WebSocket ist ein bekanntes Protokoll, das die Vollduplex-Kommunikation zwischen Client und Server ermöglicht und im Allgemeinen in Webanwendungen verwendet wird, in denen Client und Server Ereignisse mit hoher Frequenz und geringer Latenz austauschen müssen.

Spring Framework 5 hat die WebSockets-Unterstützung im Framework modernisiert und diesem Kommunikationskanal reaktive Funktionen hinzugefügt.

Wir können mehr über Spring WebFluxhere finden.

2. Maven-Abhängigkeiten

Wir werden sofort einsatzbereite Spring-Boot-Starter-Abhängigkeiten fürspring-boot-integration undspring-boot-starter-webflux verwenden, die derzeit beiSpring Milestone Repository verfügbar sind.

In diesem Beispiel verwenden wir die neueste verfügbare Version 2.0.0.M7:


    org.springframework.boot
    spring-boot-starter-integration


    org.springframework.boot
    spring-boot-starter-webflux

3. WebSocket-Konfiguration im Frühjahr

Unsere Konfiguration ist ziemlich einfach: Wir werden dieWebSocketHandler einfügen, um die Socket-Sitzung in unserer Spring WebSocket-Anwendung abzuwickeln.

@Autowired
private WebSocketHandler webSocketHandler;

Erstellen wir außerdem eine mitHandlerMapping Bean-Annotated-Methode, die für die Zuordnung zwischen Anforderungen und Handlerobjekten verantwortlich ist:

@Bean
public HandlerMapping webSocketHandlerMapping() {
    Map map = new HashMap<>();
    map.put("/event-emitter", webSocketHandler);

    SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
    handlerMapping.setOrder(1);
    handlerMapping.setUrlMap(map);
    return handlerMapping;
}

Hier sehen wir die URL, die zur Verwendung verfügbar sein wird:ws://localhost:<port>/event-emitter.

4. WebSocket-Nachrichtenbehandlung im Frühjahr

UnsereReactiveWebSocketHandler-Klasse ist für die Verwaltung der WebSocket-Sitzung auf der Serverseite verantwortlich.

Es implementiert dieWebSocketHandler-Schnittstelle, sodass wir diehandle-S-Methode überschreiben können, mit der die Nachricht an den WebSocket-Client gesendet wird:

@Component
public class ReactiveWebSocketHandler implements WebSocketHandler {

    // private fields ...

    @Override
    public Mono handle(WebSocketSession webSocketSession) {
        return webSocketSession.send(intervalFlux
          .map(webSocketSession::textMessage))
          .and(webSocketSession.receive()
            .map(WebSocketMessage::getPayloadAsText)
            .log());
    }
}

5. Erstellen eines einfachen reaktiven WebSocket-Clients

Erstellen wir jetzt einen Spring Reactive WebSocket-Client, der eine Verbindung mit unserem WebSocket-Server herstellen und Informationen austauschen kann.

Erstens die Maven-Abhängigkeiten.


    org.springframework.boot
    spring-boot-starter-webflux

Hier verwenden wir denselben Spring-Boot-Starter-Webflux, der zuvor zum Einrichten unserer reaktiven WebSocket-Serveranwendung verwendet wurde.

Jetzt erstellen wir die KlasseReactiveClientWebSocket, die für den Start der Kommunikation mit dem Server verantwortlich ist:

public class ReactiveJavaClientWebSocket {

    public static void main(String[] args) throws InterruptedException {

        WebSocketClient client = new ReactorNettyWebSocketClient();
        client.execute(
          URI.create("ws://localhost:8080/event-emitter"),
          session -> session.send(
            Mono.just(session.textMessage("event-spring-reactive-client-websocket")))
            .thenMany(session.receive()
              .map(WebSocketMessage::getPayloadAsText)
              .log())
            .then())
            .block(Duration.ofSeconds(10L));
    }
}

Im obigen Code sehen wir, dass wirReactorNettyWebSocketClient verwenden, dh die Implementierung vonWebSocketClient für die Verwendung mit Reactor Netty.

Darüber hinaus stellt die Clientverbindung zum WebSocket-Server über die URLws://localhost:8080/event-emitter,eine Sitzung her, sobald sie mit dem Server verbunden ist.

Wir können auch sehen, dass wir zusammen mit der Verbindungsanforderung eine Nachricht an den Server senden („event-spring-reactive-client-websocket“).

Darüber hinaus wird die Methodesend aufgerufen, wobei als Parameter eine Variable vom TypPublisher<T>, erwartet wird, die in unserem FallPublisher<T>Mono<T> undT einfach ist String “event-me-from-reactive-java-client-websocket“.

Darüber hinaus wird die MethodethenMany(…) aufgerufen, dieFlux vom TypString erwartet. Diereceive()-Methode ermittelt den Fluss eingehender Nachrichten, die später in Zeichenfolgen konvertiert werden.

Schließlich zwingt die Methodeblock()den Client, nach der angegebenen Zeit (in unserem Beispiel 10 Sekunden) die Verbindung zum Server zu trennen.

Stellen Sie zum Ausführen sicher, dass der Reactive WebSocket-Server aktiv ist. Starten Sie dann die KlasseReactiveJavaClientWebSocket, und im Sysout-Protokoll werden die ausgegebenen Ereignisse angezeigt:

[reactor-http-nio-4] INFO reactor.Flux.Map.1 -
onNext({"eventId":"6042b94f-fd02-47a1-911d-dacf97f12ba6",
"eventDt":"2018-01-11T23:29:26.900"})

Im Protokoll unseres Reactive WebSocket-Servers sehen wir auch die Nachricht, die der Client während des Verbindungsversuchs gesendet hat:

[reactor-http-nio-2] reactor.Flux.Map.1:
onNext(event-me-from-reactive-java-client)

Außerdem sehen wir die Meldung, dass die Verbindung beendet wurde, nachdem der Client seine Anforderungen abgeschlossen hat (in unserem Fall nach 10 Sekunden):

[reactor-http-nio-2] reactor.Flux.Map.1: onComplete()

6. Erstellen eines Browser-WebSocket-Clients

Erstellen wir ein einfaches HTML / Javascript-Client-WebSocket, um unsere reaktive WebSocket-Serveranwendung zu nutzen.

Wenn der WebSocket-Server ausgeführt wird und diese HTML-Datei in einem Browser (z. B. Chrome, Internet Explorer, Mozilla Firefox usw.) geöffnet wird, sollten die Ereignisse mit einer Verzögerung von 1 Sekunde pro Ereignis auf dem Bildschirm angezeigt werden, wie in definiert unser WebSocket Server.

{"eventId":"c25975de-6775-4b0b-b974-b396847878e6","eventDt":"2018-01-11T23:56:09.780"}
{"eventId":"ac74170b-1f71-49d3-8737-b3f9a8a352f9","eventDt":"2018-01-11T23:56:09.781"}
{"eventId":"40d8f305-f252-4c14-86d7-ed134d3e10c6","eventDt":"2018-01-11T23:56:09.782"}

7. Fazit

Hier haben wir ein Beispiel vorgestellt, wie Sie mithilfe von Spring 5 Framework eine WebSocket-Kommunikation zwischen Server und Client erstellen und die neuen reaktiven Funktionen von Spring Webflux implementieren.

Das vollständige Beispiel finden Sie wie immer in unserenGitHub repository.