Skip to content

Understanding AtmosphereInterceptor

jfarcand edited this page Feb 18, 2026 · 17 revisions

Understanding AtmosphereInterceptor

Advanced topic. Interceptors let you customize the request/response pipeline. Most applications don't need custom interceptors — @ManagedService installs the necessary ones automatically.

An AtmosphereInterceptor sits in the processing chain between the client and your handler. It can inspect, modify, or reject requests and responses.

Built-in Interceptors

These are installed automatically by @ManagedService:

Interceptor Purpose
AtmosphereResourceLifecycleInterceptor Auto-suspends connections based on transport
TrackMessageSizeInterceptor Prepends message length for guaranteed delivery
HeartbeatInterceptor Sends periodic heartbeats to keep connections alive
SuspendTrackerInterceptor Tracks suspended resources for cleanup
ManagedServiceInterceptor Routes messages to @Message annotated methods

Other useful interceptors:

Interceptor Purpose
MDCInterceptor Populates SLF4J MDC with atmosphere.uuid, atmosphere.transport, atmosphere.broadcaster for structured logging
RoomProtocolInterceptor Bridges atmosphere.js room protocol to server-side Rooms
RoomInterceptor Auto-joins resources to rooms based on URL path
BroadcastOnPostAtmosphereInterceptor Auto-broadcasts POST body to the Broadcaster
CorsInterceptor Adds CORS headers

MDCInterceptor — Structured Logging

MDCInterceptor sets SLF4J MDC keys on every request so log lines include Atmosphere context:

MDC key Value
atmosphere.uuid The unique resource identifier
atmosphere.transport Transport type (websocket, long-polling, sse, etc.)
atmosphere.broadcaster Broadcaster ID the resource is attached to

Logback pattern example:

%d{HH:mm:ss.SSS} [%thread] %-5level [uuid=%X{atmosphere.uuid} transport=%X{atmosphere.transport}] %logger{36} - %msg%n

MDC keys are automatically included as top-level fields in JSON layouts (logstash-logback-encoder, logback-contrib).

Writing a Custom Interceptor

public class LoggingInterceptor extends AtmosphereInterceptorAdapter {

    @Override
    public Action inspect(AtmosphereResource r) {
        // Called before the handler
        log.info("Request from {} via {}", r.uuid(), r.transport());

        return Action.CONTINUE;    // Proceed to next interceptor/handler
        // return Action.CANCELLED; // Stop processing (e.g., reject request)
        // return Action.SUSPEND;   // Suspend the connection
    }

    @Override
    public void postInspect(AtmosphereResource r) {
        // Called after the handler
    }

    @Override
    public void configure(AtmosphereConfig config) {
        // Called once at startup
    }
}

Registering Interceptors

Via @ManagedService

@ManagedService(path = "/chat",
    interceptors = {LoggingInterceptor.class, RateLimitInterceptor.class})
public class Chat { /* ... */ }

These are appended to the default set — they don't replace it.

Via Annotation

@AtmosphereInterceptorService
public class LoggingInterceptor extends AtmosphereInterceptorAdapter {
    // Auto-registered when annotation scanning is enabled
}

Programmatically

framework.interceptor(new LoggingInterceptor());

Interceptor Priority

Control execution order with PRIORITY:

public class EarlyInterceptor extends AtmosphereInterceptorAdapter {
    @Override
    public PRIORITY priority() {
        return InvokationOrder.BEFORE_DEFAULT;  // Run before defaults
        // InvokationOrder.AFTER_DEFAULT       // Run after defaults (default)
        // InvokationOrder.FIRST_BEFORE_DEFAULT // Run first, before everything
    }
}

Clone this wiki locally