WebSockets réactifs avec Spring 5

WebSockets réactives avec Spring 5

1. Vue d'ensemble

Dans cet article, nous allons créer un exemple rapide utilisant la nouvelle API Spring Framework 5 WebSockets ainsi que les fonctionnalités réactives fournies par Spring WebFlux Framework.

WebSocket est un protocole bien connu qui permet la communication en duplex intégral entre le client et le serveur, généralement utilisé dans les applications Web où le client et le serveur doivent échanger des événements à haute fréquence et avec une latence faible.

Spring Framework 5 a modernisé la prise en charge de WebSockets dans le cadre, ajoutant des fonctionnalités réactives à ce canal de communication.

Nous pouvons en trouver plus sur Spring WebFluxhere.

2. Dépendances Maven

Nous allons utiliser des dépendances prêtes à l'emploi pourspring-boot-integration etspring-boot-starter-webflux, actuellement disponibles àSpring Milestone Repository.

Dans cet exemple, nous utilisons la dernière version disponible, 2.0.0.M7:


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


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

3. Configuration de WebSocket au printemps

Notre configuration est assez simple: nous allons injecter lesWebSocketHandler pour gérer la session socket dans notre application Spring WebSocket.

@Autowired
private WebSocketHandler webSocketHandler;

De plus, créons une méthode annotée par le beanHandlerMapping qui sera responsable du mappage entre les requêtes et les objets gestionnaires:

@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;
}

Ici, nous pouvons voir l'URL qui sera disponible pour l'utilisation:ws://localhost:<port>/event-emitter.

4. Gestion des messages WebSocket au printemps

Notre classeReactiveWebSocketHandler sera responsable de la gestion de la session WebSocket côté serveur.

Il implémente l'interfaceWebSocketHandler afin que nous puissions remplacer la méthodehandle, qui sera utilisée pour envoyer le message au client WebSocket:

@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. Création d'un client WebSocket réactif simple

Créons maintenant un client Spring Reactive WebSocket qui pourra se connecter et échanger des informations avec notre serveur WebSocket.

Tout d'abord, les dépendances Maven.


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

Ici, nous utilisons le même spring-boot-starter-webflux utilisé précédemment pour configurer notre application serveur WebSocket réactive.

Maintenant, créons la classeReactiveClientWebSocket, chargée de démarrer la communication avec le serveur:

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));
    }
}

Dans le code ci-dessus, nous pouvons voir que nous utilisons leReactorNettyWebSocketClient, qui est l'implémentation deWebSocketClient à utiliser avec Reactor Netty.

En outre, la connexion client au serveur WebSocket via l'URLws://localhost:8080/event-emitter, établit une session dès qu'elle est connectée au serveur.

Nous pouvons également voir que nous envoyons un message au serveur («event-spring-reactive-client-websocket») avec la demande de connexion.

De plus, la méthodesend est invoquée, en attendant comme paramètre une variable de typePublisher<T>, qui dans notre cas notrePublisher<T> estMono<T> etT est un simple Chaîne «event-me-from-reactive-java-client-websocket».

De plus, la méthodethenMany(…) attend unFlux de typeString est invoquée. La méthodereceive() récupère le flux des messages entrants, qui sont ensuite convertis en chaînes.

Enfin, la méthodeblock() oblige le client à se déconnecter du serveur après le temps donné (10 secondes dans notre exemple).

Pour l'exécuter, assurez-vous que Reactive WebSocket Server est opérationnel. Ensuite, lancez la classeReactiveJavaClientWebSocket, et nous pouvons voir sur le journal sysout les événements émis:

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

Nous pouvons également voir dans le journal de notre serveur Reactive WebSocket le message envoyé par le client lors de la tentative de connexion:

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

En outre, nous pouvons voir le message de la connexion terminée après que le client a terminé ses demandes (dans notre cas, après les 10 secondes):

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

6. Création d'un navigateur WebSocket Client

Créons un simple client HTML / Javascript WebSocket pour utiliser notre application serveur WebSocket réactive.

Lorsque le serveur WebSocket est en cours d’exécution et que vous ouvrez ce fichier HTML dans un navigateur (par exemple, Chrome, Internet Explorer, Mozilla Firefox, etc.), les événements doivent être affichés à l’écran, avec un délai de 1 seconde par événement, comme défini dans notre serveur WebSocket.

{"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. Conclusion

Nous avons présenté ici un exemple de création d'une communication WebSocket entre le serveur et le client à l'aide de Spring 5 Framework, en implémentant les nouvelles fonctionnalités réactives fournies par Spring Webflux.

Comme toujours, l'exemple complet se trouve dans nosGitHub repository.