WebSockets are a popular method for enabling real-time communication in your applications, offering an alternative to techniques like long polling and server-sent events. This article will guide you through implementing WebSockets in a Spring Boot application, covering both server and client setup. We’ll use STOMP, a messaging protocol layered over WebSockets, for communication.
Our server-side code will be written in Java. For the client, we’ll use both Java and JavaScript (with SockJS) examples, as WebSocket clients are typically found in front-end applications. Our code will showcase broadcasting messages to multiple users (pub-sub model) and sending messages to individual users. We’ll also touch on securing WebSockets and ensuring our solution remains functional even without native WebSocket support.
It’s important to note that securing WebSockets is a complex topic and will only be briefly covered here. This, along with factors discussed in the WebSocket in Production? section, means I recommend making modifications before using this setup in production. Read on for a production-ready approach with enhanced security.
WebSocket and STOMP Protocols
The WebSocket protocol allows two applications to communicate in both directions. It starts with a standard HTTP handshake. Once that’s complete, the connection upgrades to a TCP/IP connection, which the WebSocket then uses.
As a low-level protocol, WebSocket defines how bytes are converted into frames, which can carry text or binary messages. Without extra information on routing or processing, building complex applications solely with WebSockets is difficult. That’s why the specification allows for sub-protocols that operate at a higher level. One such sub-protocol supported by Spring is STOMP.
STOMP is a text-based messaging protocol initially designed to connect scripting languages like Ruby, Python, and Perl to enterprise message brokers. It enables cross-language communication for sending and receiving messages. The analogy of WebSocket being “TCP for the Web” extends to STOMP being “HTTP for the Web.” STOMP defines various frame types, such as CONNECT, SUBSCRIBE, UNSUBSCRIBE, ACK, and SEND, mapped onto WebSocket frames. These commands simplify communication management and enable features like message acknowledgment.
The Server-side: Spring Boot and WebSockets
Leveraging the Spring Boot framework, we can rapidly develop the WebSocket server-side of our application. Spring Boot’s spring-WebSocket module offers compatibility with the Java WebSocket API standard (JSR-356).
Let’s break down the implementation into manageable steps:
Step 1. Begin by adding the WebSocket library dependency:
| |
For transmitting messages in JSON format, include the GSON or Jackson dependency. Additionally, a security framework like Spring Security might be necessary.
Step 2. Configure Spring to enable WebSocket and STOMP messaging.
| |
The configureMessageBroker method accomplishes two tasks:
- It establishes an in-memory message broker with destinations for sending and receiving messages. In this example,
topicandqueueare used as prefixes. By convention, destinations for broadcasting messages to all subscribed clients (pub-sub) are prefixed withtopic. Destinations for private messages use thequeueprefix. - It defines the
appprefix for filtering destinations handled by controller methods annotated with@MessageMapping. The controller processes incoming messages before sending them to the broker.

The withSockJS() call enables SockJS fallback options, ensuring WebSockets function even without native browser support. We’ll delve into this further later.
The setAllowedOrigins() method on the endpoint is crucial when the client and server reside on different domains. By default, WebSocket and SockJS only allow same-origin requests, so this method enables cross-domain communication.
Step 3. Create a controller to handle user requests and broadcast received messages to all subscribed users.
This example demonstrates a method that sends messages to the /topic/news destination:
| |
As an alternative to @SendTo, autowire SimpMessagingTemplate inside your controller.
| |
To enhance security, consider adding classes like ResourceServerConfigurerAdapter or WebSecurityConfigurerAdapter from the Spring Security framework in later steps. Implementing a message model for mapping transmitted JSON to objects can also be beneficial.
Building the WebSocket Client
Creating the client is even more straightforward.
Step 1. Autowire the Spring STOMP client.
| |
Step 2. Open a connection.
| |
Now we can send messages to a specific destination, reaching all subscribed users.
| |
Subscribing to messages is just as easy.
| |
Sometimes, sending messages to a specific user (like in a chat application) requires a dedicated destination. This private conversation destination can be created by appending a unique identifier, such as /queue/chat-user123, to a general destination name. HTTP session or STOMP session identifiers are suitable for this purpose.
Spring simplifies this process with the @SendToUser annotation. When a controller method uses this annotation, UserDestinationMessageHandler handles the destination based on the session identifier. Client-side subscriptions to destinations prefixed with /user are transformed into user-specific destinations. On the server, user destinations are resolved using the user’s Principal object.
Here’s an example of using @SendToUser on the server:
| |
You can achieve the same result with SimpMessagingTemplate.
| |
Let’s explore a JavaScript (SockJS) client that receives private messages from the Java code above. Modern browsers (Internet Explorer 10 and later) support WebSockets as part of the HTML5 specification.
| |
To receive private messages, the client subscribes to the general destination /queue/greetings prefixed with /user. No unique identifiers are needed. However, the client must log in to the application beforehand, initializing the Principal object on the server.
Securing WebSockets
Cookie-based authentication is common in web applications. For example, Spring Security can restrict access to specific pages or controllers based on user login status. The user’s security context is maintained through a cookie-based HTTP session, subsequently associated with the user’s WebSocket or SockJS sessions. Securing WebSockets endpoints can be achieved similarly to other requests, like using Spring’s WebSecurityConfigurerAdapter.
Modern web applications often utilize REST APIs with OAuth/JWT tokens for authentication and authorization. While the WebSocket protocol doesn’t explicitly define client authentication during the HTTP handshake, standard HTTP headers like “Authorization” are commonly used. Unfortunately, not all STOMP clients support this. Spring’s Java STOMP client allows setting headers for the handshake:
| |
However, the SockJS JavaScript client doesn’t support sending authorization headers. As a workaround, you can send query parameters containing the token, which requires custom server-side code to read, validate, and prevent tokens from being logged alongside requests (a potential security risk).
SockJS Fallback Options
Integrating WebSockets can be tricky. Older browsers (like IE 9) lack support, and restrictive proxies might prevent the HTTP upgrade or sever long-lived connections. SockJS addresses these challenges with fallback options.
SockJS transports are categorized into WebSockets, HTTP Streaming, and HTTP Long Polling. It starts by sending a GET /info request to gather server information. Based on the response, it chooses the appropriate transport: WebSockets first, then Streaming if possible, and finally Polling as the last resort.
WebSocket in Production?
While functional, this setup isn’t ideal for production. Spring Boot supports integrating full-fledged messaging systems like ActiveMQ or RabbitMQ that handle the STOMP protocol. These external brokers often support more STOMP operations (e.g., acknowledgments, receipts) than the simple broker we used. STOMP Over WebSocket offers valuable insights into WebSockets and STOMP, listing messaging systems that could be better suited for production environments.
Consider an external message broker if your application demands high scalability and robustness, especially when clustering the message broker becomes necessary (Spring’s simple broker doesn’t support clustering). In such cases, instead of enabling the simple broker in WebSocketConfig, enable the Stomp broker relay to forward messages to and from the external broker.
To further your Java development journey with Spring Boot, explore Using Spring Boot for OAuth2 and JWT REST Protection next.