Mastering WebSocket Integration in Spring Boot: Javax, WebMVC & WebFlux
This article compares six WebSocket integration approaches—Javax, WebMVC, WebFlux, Java-WebSocket, SocketIO, and Netty—showing how to configure both server and client sides in Spring Boot, with step‑by‑step code examples, key annotations, and practical tips for each method.
Javax WebSocket (javax.websocket)
The javax.websocket API follows the JSR‑356 specification. A server endpoint is defined by annotating a class with @ServerEndpoint and implementing lifecycle callbacks:
@Component
@ServerEndpoint("/websocket/{type}")
public class JavaxWebSocketServerEndpoint {
@OnOpen
public void onOpen(Session session, EndpointConfig config, @PathParam("type") String type) {
// connection established
}
@OnClose
public void onClose(Session session, CloseReason reason) { }
@OnMessage
public void onMessage(Session session, String message) { }
@OnMessage
public void onMessage(Session session, PongMessage message) { }
@OnMessage
public void onMessage(Session session, ByteBuffer message) { }
@OnError
public void onError(Session session, Throwable e) { }
}Spring Boot requires the spring-boot-starter-websocket starter and a bean of type ServerEndpointExporter to expose the endpoint:
implementation 'org.springframework.boot:spring-boot-starter-websocket'
@Configuration(proxyBeanMethods = false)
public class JavaxWebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}Client code uses @ClientEndpoint with the same callbacks. The connection is obtained via ContainerProvider.getWebSocketContainer() and connectToServer:
@ClientEndpoint
public class JavaxWebSocketClientEndpoint { /* callbacks omitted for brevity */ }
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
Session session = container.connectToServer(JavaxWebSocketClientEndpoint.class, uri);Note: The API defines PongMessage but not PingMessage. Ping frames are usually answered automatically by the peer. Manual ping/pong can be sent with session.getAsyncRemote().sendPing(...) and sendPong(...).
WebMVC WebSocket Integration
WebMVC uses Spring's WebSocketHandler interface. Add the same starter dependency and implement a handler:
implementation 'org.springframework.boot:spring-boot-starter-websocket'
public class ServletWebSocketServerHandler implements WebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session) { }
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) { }
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) { }
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) { }
@Override
public boolean supportsPartialMessages() { return false; }
}Register the handler in a configuration class:
@Configuration
@EnableWebSocket
public class ServletWebSocketServerConfigurer implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ServletWebSocketServerHandler(), "/websocket")
.setAllowedOrigins("*");
}
}Handshake interception can be added by implementing HandshakeInterceptor. The default registration stores handlers in a Map<String, WebSocketHandler>, so Ant‑style wildcards (e.g., /websocket/**) are not supported out of the box. A custom UrlPathHelper can be injected to enable pattern matching:
@Configuration
@EnableWebSocket
public class ServletWebSocketServerConfigurer implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
if (registry instanceof ServletWebSocketHandlerRegistry) {
((ServletWebSocketHandlerRegistry) registry)
.setUrlPathHelper(new PrefixUrlPathHelper("/websocket"));
}
registry.addHandler(new ServletWebSocketServerHandler(), "/websocket/**")
.setAllowedOrigins("*");
}
public static class PrefixUrlPathHelper extends UrlPathHelper {
private final String prefix = "/websocket";
@Override
public String resolveAndCacheLookupPath(HttpServletRequest request) {
String path = super.resolveAndCacheLookupPath(request);
return path.startsWith(prefix) ? prefix + "/**" : path;
}
}
}Client side can use StandardWebSocketClient (or container‑specific implementations) together with WebSocketConnectionManager:
WebSocketClient client = new StandardWebSocketClient();
WebSocketHandler handler = new ServletWebSocketClientHandler();
WebSocketConnectionManager manager = new WebSocketConnectionManager(client, handler, uri);
manager.start();WebFlux Reactive WebSocket Integration
WebFlux works with reactive types; no extra dependency beyond spring-boot-starter-webflux is needed.
public class ReactiveWebSocketServerHandler implements WebSocketHandler {
@Override
public Mono<Void> handle(WebSocketSession session) {
Mono<Void> send = session.send(Flux.create(sink -> {
// sink.next(message) to push data
})).doOnError(e -> { /* handle */ });
Mono<Void> receive = session.receive()
.doOnNext(msg -> { /* process */ })
.doOnError(e -> { /* handle */ })
.then();
return Mono.zip(send, receive).then();
}
}Map the handler to a URL via a SimpleUrlHandlerMapping bean:
@Component
public class ReactiveWebSocketServerHandlerMapping extends SimpleUrlHandlerMapping {
public ReactiveWebSocketServerHandlerMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/websocket/**", new ReactiveWebSocketServerHandler());
setUrlMap(map);
setOrder(100); // ensure precedence
}
}Enable the reactive stack with a WebSocketHandlerAdapter bean:
@Configuration(proxyBeanMethods = false)
public class ReactiveWebSocketConfiguration {
@Bean
public WebSocketHandlerAdapter webSocketHandlerAdapter() {
return new WebSocketHandlerAdapter();
}
}Reactive client example (Reactor Netty implementation):
WebSocketClient client = new ReactorNettyWebSocketClient();
WebSocketHandler handler = new ReactiveWebSocketClientHandler();
client.execute(uri, handler).subscribe();Both server and client can send text, binary, ping, and pong messages using the FluxSink<WebSocketMessage> obtained from the session.
Other WebSocket Libraries
Java-WebSocket – pure‑Java library. GitHub: https://github.com/TooTallNate/Java-WebSocket
Socket.IO – protocol wrapper for real‑time chat. Server and client artifacts: socket.io-server-java, socket.io-client-java. GitHub: https://github.com/socketio
Netty – low‑level networking framework offering full control over handshake and frame handling. GitHub: https://github.com/netty/netty
Key Takeaways
Spring Boot supports three integration styles: standard JSR‑356 ( javax.websocket), servlet‑based WebSocketHandler (WebMVC), and reactive WebSocketHandler (WebFlux).
Choose the style that matches your application architecture: blocking MVC for classic servlet apps, reactive for WebFlux, or the standards‑based JSR‑356 API for portability.
All approaches share similar lifecycle callbacks; differences lie in configuration beans and how messages are sent/received.
For advanced scenarios—custom handshake logic, pattern‑based paths, or container‑specific client implementations—consider extending Spring’s helper classes or using a lower‑level library such as Netty.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
