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.