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.

Architect
Architect
Architect
Mastering WebSocket Integration in Spring Boot: Javax, WebMVC & WebFlux

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentSpring BootWebSocketWebFluxJavaxwebmvc
Architect
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.