-
-
Notifications
You must be signed in to change notification settings - Fork 755
Understanding ManagedService
jfarcand edited this page Feb 18, 2026
·
2 revisions
@ManagedService is the recommended way to build Atmosphere applications. It provides an annotation-driven programming model with automatic lifecycle management, message encoding/decoding, and dependency injection.
@ManagedService(path = "/chat")
public class Chat {
@Inject
private BroadcasterFactory factory;
@Inject
private AtmosphereResource r;
@Inject
private AtmosphereResourceEvent event;
@Ready
public void onReady() {
// Connection is suspended and ready to receive messages
}
@Disconnect
public void onDisconnect() {
if (event.isCancelled()) {
// Unexpected disconnect
} else if (event.isClosedByClient()) {
// Client closed the connection
}
}
@Message(encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})
public Message onMessage(Message message) {
// Return value is broadcast to all connected clients
return message;
}
@Heartbeat
public void onHeartbeat(AtmosphereResourceEvent event) {
// Client heartbeat received
}
}When you annotate a class with @ManagedService, Atmosphere automatically installs:
| Component | Purpose |
|---|---|
UUIDBroadcasterCache |
Caches messages so reconnecting clients don't miss data |
AtmosphereResourceLifecycleInterceptor |
Manages connection suspend/resume lifecycle |
TrackMessageSizeInterceptor |
Guarantees complete message delivery |
HeartbeatInterceptor |
Keeps connections alive across proxies |
SuspendTrackerInterceptor |
Tracks suspended connections |
| Attribute | Type | Default | Description |
|---|---|---|---|
path |
String |
"/" |
URL mapping for this handler |
broadcaster |
Class |
DefaultBroadcaster.class |
Broadcaster implementation |
broadcasterCache |
Class |
UUIDBroadcasterCache.class |
Message cache implementation |
interceptors |
Class[] |
{} |
Additional interceptors (appended to defaults) |
broadcastFilters |
Class[] |
{} |
Message filters applied before broadcast |
listeners |
Class[] |
{} |
Event listeners for connection tracking |
atmosphereConfig |
String[] |
{} |
Key-value config (e.g. "org.atmosphere.cpr.maxInactiveActivity=120000") |
| Annotation | When Invoked | Typical Use |
|---|---|---|
@Ready |
Connection suspended and ready | Log connection, send welcome message |
@Disconnect |
Client disconnects | Clean up, notify others |
@Message |
Message received from Broadcaster | Process and optionally re-broadcast |
@Heartbeat |
Client heartbeat received | Logging, presence tracking |
| Annotation | Description |
|---|---|
@Get |
Handle HTTP GET (e.g. set response encoding) |
@Post |
Handle HTTP POST |
@Put |
Handle HTTP PUT |
@Delete |
Handle HTTP DELETE |
| Annotation | Target | Description |
|---|---|---|
@Singleton |
Class | Single instance shared across all connections |
@PathParam |
Field | Bind URI template variable (e.g. /chat/{room}) |
@DeliverTo |
Method | Control broadcast scope: RESOURCE, BROADCASTER, or ALL
|
@ManagedService classes support @Inject (Jakarta CDI) for:
@Inject private AtmosphereResource r; // Current connection
@Inject private AtmosphereResourceEvent event; // Current event
@Inject private BroadcasterFactory factory; // Create/lookup broadcasters
@Inject @Named("/chat") private Broadcaster b; // Named broadcasterThe @Message annotation supports automatic type conversion:
// Encoder: converts your object to a String for the wire
public class JacksonEncoder implements Encoder<Message, String> {
@Inject private ObjectMapper mapper;
@Override
public String encode(Message m) {
return mapper.writeValueAsString(m);
}
}
// Decoder: converts incoming String to your object
public class JacksonDecoder implements Decoder<String, Message> {
@Inject private ObjectMapper mapper;
@Override
public Message decode(String s) {
return mapper.readValue(s, Message.class);
}
}
// Usage
@Message(encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})
public Message onMessage(Message message) {
return message; // Automatically decoded from JSON, re-encoded for broadcast
}Use @PathParam to capture URI variables:
@ManagedService(path = "/chat/{room}")
public class Chat {
@PathParam("room")
private String roomName;
@Ready
public void onReady() {
// roomName is populated from the URL
// e.g. /chat/lobby → roomName = "lobby"
}
}Each unique path creates a separate Broadcaster, so /chat/lobby and /chat/general have independent message streams.
Control who receives the return value of a @Message method:
@Message
@DeliverTo(DeliverTo.DELIVER_TO.BROADCASTER) // All connections on this path
public String onMessage(String message) {
return "Echo: " + message;
}
@Message
@DeliverTo(DeliverTo.DELIVER_TO.RESOURCE) // Only the sender
public String onPrivateMessage(String message) {
return "Only you see this";
}Pass Atmosphere config via the atmosphereConfig attribute:
@ManagedService(
path = "/chat",
atmosphereConfig = {
"org.atmosphere.cpr.maxInactiveActivity=120000",
"org.atmosphere.websocket.maxTextMessageSize=65536"
}
)- Understanding @RoomService — a room-aware alternative that auto-creates Rooms with presence and history
- Understanding Rooms — the Room API for named groups
- Understanding Broadcaster — the underlying pub/sub bus