skip to content

STOMP Over WebSocket

STOMP adds destinations and subscriptions over the socket, served either by Spring's simple in-memory broker or relayed to RabbitMQ or ActiveMQ. Interviewers ask what breaks with the simple broker once you scale to several instances.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

5

What is STOMP over WebSocket in Spring, and what does @EnableWebSocketMessageBroker set up?

level: juniorimportance: must knowfreq 70%

answer

  1. WebSocket = pipe, STOMP = pub/sub on top
  2. @EnableWebSocketMessageBroker + WebSocketMessageBrokerConfigurer
  3. registerStompEndpoints + configureMessageBroker
  4. SUBSCRIBE / SEND / MESSAGE frames
  5. /ws endpoint, withSockJS fallback

basics

~20 s

WebSocket is a raw two-way connection; STOMP is a simple text messaging protocol layered on top that adds destinations (like topics). @EnableWebSocketMessageBroker turns on Spring's message-broker support so clients can subscribe and publish over WebSocket.

solid answer

~40 s

A raw WebSocket only gives you a bidirectional byte/text pipe with no message semantics. STOMP (Simple Text Oriented Messaging Protocol) is a lightweight, frame-based sub-protocol that adds a pub/sub model on top: clients SUBSCRIBE to destinations and SEND to destinations. Spring's @EnableWebSocketMessageBroker (on a @Configuration class implementing WebSocketMessageBrokerConfigurer) activates the full messaging stack: you register the STOMP endpoint clients connect to (registerStompEndpoints), and configure the message broker and destination prefixes (configureMessageBroker). This lets you write @MessageMapping controller methods that handle incoming messages and route outgoing ones to a broker, rather than manually managing raw WebSocketHandler callbacks. It's the higher-level programming model, analogous to how @RestController sits above raw servlets.

code

java · 15 lines
java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app");
        registry.enableSimpleBroker("/topic", "/queue");
    }
}

go deeper

for a junior

Know that WebSocket is the transport and STOMP adds pub/sub semantics; @EnableWebSocketMessageBroker turns it on.

for a middle

Be able to write the config class with both override methods and explain the client message flow.

for a senior

Explain how the annotation handler, channels, and broker wire together, and the security implications of per-frame authorization.

for a principal

Weigh STOMP-over-WebSocket vs SSE vs raw WebSocket, and factor in the operational cost of the messaging stack for the use case.

### The layers **WebSocket** is a transport: after an HTTP handshake it upgrades the connection to a persistent, full-duplex TCP channel over which either side can push text or binary frames at any time. But WebSocket by itself defines *no application semantics* — no concept of a 'topic', 'subscribe', or message routing. If you used Spring's raw `WebSocketHandler`, you'd have to invent your own message format and routing. **STOMP** (Simple/Streaming Text Oriented Messaging Protocol) is a simple, broker-neutral sub-protocol negotiated during the WebSocket handshake (`Sec-WebSocket-Protocol: v12.stomp`). It gives you a small set of frame commands — `CONNECT`, `SUBSCRIBE`, `SEND`, `MESSAGE`, `UNSUBSCRIBE`, `ACK`, `DISCONNECT` — each with a command line, headers (including a `destination`), and a body. This makes the connection a **pub/sub messaging channel**: clients subscribe to destinations like `/topic/prices` and send to destinations like `/app/greeting`. ### What @EnableWebSocketMessageBroker does Put it on a `@Configuration` class that implements `WebSocketMessageBrokerConfigurer`. It imports Spring's messaging infrastructure and expects you to override two methods: - `registerStompEndpoints(StompEndpointRegistry)` — declares the HTTP URL where clients open the WebSocket + STOMP connection, e.g. `registry.addEndpoint("/ws").withSockJS()`. `withSockJS()` adds a fallback for browsers/proxies that can't do native WebSocket. - `configureMessageBroker(MessageBrokerRegistry)` — declares destination prefixes and which broker handles them (see below). Once enabled, Spring wires up: a `clientInboundChannel` (messages from clients), a `SimpAnnotationMethodMessageHandler` that dispatches to your `@MessageMapping` methods, the broker (simple in-memory or a relay to RabbitMQ/ActiveMQ), and a `clientOutboundChannel` (messages back to clients). ### The message flow 1. Client opens WebSocket to `/ws`, sends STOMP `CONNECT`. 2. Client `SUBSCRIBE`s to `/topic/greetings`. 3. Client `SEND`s to `/app/hello`. 4. Spring routes `/app/**` messages to your `@MessageMapping("/hello")` controller method (application destinations). 5. The method's return value (with `@SendTo("/topic/greetings")`) is published to the broker, which fans it out to all subscribers. ### When to use Use STOMP-over-WebSocket for interactive, low-latency, multi-user push: chat, live dashboards, notifications, collaborative editing, live sports/price feeds. If you only need occasional server-to-client push and not a full pub/sub model, Server-Sent Events (SSE) may be simpler. ### Gotchas - You still need Spring Security config for the WebSocket handshake and message authorization — the normal HTTP filter chain only covers the handshake, not individual STOMP frames. - SockJS and native WebSocket have different endpoint URLs/behaviors; the client library must match.

  • What does withSockJS() add and why would you need it?
    It enables the SockJS fallback protocol, so clients behind proxies or in browsers without native WebSocket support can still get a WebSocket-like connection via HTTP streaming/long-polling transports.
  • Is STOMP required to use WebSocket in Spring?
    No. You can implement a raw WebSocketHandler and define your own message format. STOMP is the higher-level, broker-backed option that gives you pub/sub routing and @MessageMapping controllers for free.

context

open as a page

Explain application vs broker destination prefixes and how @MessageMapping / @SendTo route messages.

level: middleimportance: must knowfreq 68%

basics

~20 s

Application prefixes (like /app) route incoming client messages to your @MessageMapping controller methods. Broker prefixes (like /topic, /queue) go straight to the broker for subscription/fan-out. @SendTo names the broker destination the method's return value is published to.

open as a page

How do you push messages to WebSocket clients from arbitrary server code (outside a @MessageMapping handler)?

level: middleimportance: should knowfreq 58%

basics

~20 s

Inject SimpMessagingTemplate and call convertAndSend(destination, payload) to broadcast to a topic, or convertAndSendToUser(user, destination, payload) to reach one user. This works from any bean — a service, scheduler, or event listener — not just message handlers.

open as a page

Compare the in-memory simple broker with the StompBrokerRelay (RabbitMQ/ActiveMQ). When and why switch?

level: seniorimportance: should knowfreq 55%

basics

~20 s

The simple broker keeps subscriptions and does fan-out in the app's memory — easy but single-instance and non-durable. The StompBrokerRelay forwards STOMP frames to a real broker (RabbitMQ/ActiveMQ), so multiple app instances share subscriptions and you get scaling and reliability.

open as a page

How would you architect and secure a horizontally-scaled STOMP-over-WebSocket system, and what failure modes matter?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Use an external STOMP broker relay so all app instances share subscriptions, authenticate and authorize at both the handshake and per-message level, plan for sticky/routable connections at the load balancer, and design for broker and relay failures with reconnection and backpressure handling.

open as a page