WebSockets reativos com mola 5

WebSockets reativos com mola 5

1. Visão geral

Neste artigo, vamos criar um exemplo rápido usando a nova API Spring Framework 5 WebSockets junto com recursos reativos fornecidos pela Spring WebFlux Framework.

O WebSocket é um protocolo conhecido que permite a comunicação full-duplex entre cliente e servidor, geralmente usada em aplicativos da Web em que o cliente e o servidor precisam trocar eventos em alta frequência e com baixa latência.

O Spring Framework 5 modernizou o suporte a WebSockets na estrutura, adicionando recursos reativos a esse canal de comunicação.

Podemos encontrar mais no Spring WebFluxhere.

2. Dependências do Maven

Vamos usar dependências de arranque com mola paraspring-boot-integrationespring-boot-starter-webflux, atualmente disponíveis emSpring Milestone Repository.

Neste exemplo, estamos usando a versão mais recente disponível, 2.0.0.M7:


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


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

3. Configuração WebSocket no Spring

Nossa configuração é bastante direta: injetaremosWebSocketHandler para lidar com a sessão de soquete em nosso aplicativo Spring WebSocket.

@Autowired
private WebSocketHandler webSocketHandler;

Além disso, vamos criar um método anotado por beanHandlerMapping que será responsável pelo mapeamento entre as solicitações e os objetos do manipulador:

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

Aqui podemos ver o URL que estará disponível para uso:ws://localhost:<port>/event-emitter.

4. Tratamento de mensagens WebSocket na primavera

Nossa classeReactiveWebSocketHandler será responsável por gerenciar a sessão WebSocket no lado do servidor.

Ele implementa a interfaceWebSocketHandler para que possamos substituir o métodohandle, que será usado para enviar a mensagem ao cliente 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. Criação de um cliente WebSocket reativo simples

Vamos agora criar um cliente Spring Reactive WebSocket que será capaz de se conectar e trocar informações com nosso servidor WebSocket.

Primeiro, as dependências do Maven.


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

Aqui, estamos usando o mesmo spring-boot-starter-webflux usado anteriormente para configurar nosso aplicativo de servidor WebSocket reativo.

Agora, vamos criar a classeReactiveClientWebSocket, responsável por iniciar a comunicação com o servidor:

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

No código acima, podemos ver que estamos usandoReactorNettyWebSocketClient, que é a implementaçãoWebSocketClient para uso com o Reactor Netty.

Além disso, o cliente se conecta ao servidor WebSocket por meio da URLws://localhost:8080/event-emitter,, estabelecendo uma sessão assim que é conectado ao servidor.

Também podemos ver que estamos enviando uma mensagem ao servidor (“event-spring-reactive-client-websocket“) junto com a solicitação de conexão.

Além disso, o métodosend é invocado, esperando como parâmetro uma variável do tipoPublisher<T>, que em nosso casoPublisher<T> éMono<T> eT é um simples String “event-me-from-reactive-java-client-websocket“.

Além disso, o métodothenMany(…) esperando umFlux do tipoString é chamado. O métodoreceive() obtém o fluxo de mensagens de entrada, que mais tarde são convertidas em strings.

Finalmente, o métodoblock() força o cliente a se desconectar do servidor após o tempo determinado (10 segundos em nosso exemplo).

Para executá-lo, verifique se o Reactive WebSocket Server está funcionando. Em seguida, inicie a classeReactiveJavaClientWebSocket, e poderemos ver no log do sysout os eventos sendo emitidos:

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

Também podemos ver no log do nosso servidor Reactive WebSocket a mensagem enviada pelo cliente durante a tentativa de conexão:

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

Além disso, podemos ver a mensagem de conexão encerrada após o cliente concluir seus pedidos (no nosso caso, após os 10 segundos):

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

6. Criação de um cliente WebSocket do navegador

Vamos criar um WebSocket cliente HTML / Javascript simples para consumir nosso aplicativo de servidor WebSocket reativo.

Com o servidor WebSocket em execução, abrindo esse arquivo HTML em um navegador (por exemplo: Chrome, Internet Explorer, Mozilla Firefox etc.), devemos ver os eventos sendo impressos na tela, com um atraso de 1 segundo por evento, conforme definido em nosso servidor 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. Conclusão

Aqui, apresentamos um exemplo de como criar uma comunicação WebSocket entre o servidor e o cliente usando o Spring 5 Framework, implementando os novos recursos reativos fornecidos pelo Spring Webflux.

Como sempre, o exemplo completo pode ser encontrado em nossoGitHub repository.