Skip to content

Navigation Menu

Sign in
Sign up
jfarcand edited this page Feb 25, 2026 · 2 revisions

gRPC Transport

Atmosphere 4.0 includes a gRPC transport module (atmosphere-grpc) that enables bidirectional streaming between clients and server over HTTP/2 using Protocol Buffers. It works standalone or alongside the servlet-based transports in Spring Boot.

Architecture

gRPC Client AtmosphereGrpcServer
 │ │
 ├── SUBSCRIBE /chat ────────────→│ AtmosphereGrpcService
 │ │ ↓
 │←── ACK (tracking_id) ─────────│ GrpcProcessor
 │ │ ↓
 ├── MESSAGE "Hello" ────────────→│ GrpcHandler.onMessage()
 │ │ ↓
 │←── MESSAGE "Hello" ───────────│ Broadcaster.broadcast()
 │ │

The gRPC transport maps onto Atmosphere's core abstractions: each gRPC stream becomes an AtmosphereResource, subscribes to a Broadcaster, and participates in the same pub/sub model as WebSocket and SSE clients.

Quick Start — Standalone

1. Add the dependency

<dependency>
 <groupId>org.atmosphere</groupId>
 <artifactId>atmosphere-grpc</artifactId>
 <version>4.0.4</version>
</dependency>

2. Create a handler

public class ChatGrpcHandler extends GrpcHandlerAdapter {
 @Override
 public void onOpen(GrpcChannel channel) {
 log.info("gRPC client connected: {}", channel.uuid());
 }
 @Override
 public void onMessage(GrpcChannel channel, String message) {
 log.info("gRPC message from {}: {}", channel.uuid(), message);
 }
 @Override
 public void onClose(GrpcChannel channel) {
 log.info("gRPC client disconnected: {}", channel.uuid());
 }
}

3. Start the server

var framework = new AtmosphereFramework();
try (var server = AtmosphereGrpcServer.builder()
 .framework(framework)
 .port(9090)
 .handler(new ChatGrpcHandler())
 .enableReflection(true)
 .build()) {
 server.start();
 server.awaitTermination();
}

4. Test with grpcurl

# List available services
grpcurl -plaintext localhost:9090 list
# Subscribe and send a message
grpcurl -plaintext -d '{"type":"SUBSCRIBE","topic":"/chat"}' \
 localhost:9090 org.atmosphere.grpc.AtmosphereService/Stream

Proto Schema

The gRPC transport uses a single bidirectional streaming RPC:

syntax = "proto3";
package org.atmosphere.grpc;
service AtmosphereService {
 rpc Stream(stream AtmosphereMessage) returns (stream AtmosphereMessage);
}
message AtmosphereMessage {
 MessageType type = 1;
 string topic = 2;
 string payload = 3;
 bytes binary_payload = 4;
 map<string, string> headers = 5;
 string tracking_id = 6;
}
enum MessageType {
 SUBSCRIBE = 0;
 UNSUBSCRIBE = 1;
 MESSAGE = 2;
 HEARTBEAT = 3;
 ACK = 4;
 ERROR = 5;
}

GrpcHandler

The GrpcHandler interface defines lifecycle callbacks for gRPC connections:

Callback When Fired
onOpen(GrpcChannel) Stream established
onMessage(GrpcChannel, String) Text message received
onBinaryMessage(GrpcChannel, byte[]) Binary message received
onClose(GrpcChannel) Stream closed
onError(GrpcChannel, Throwable) Error occurred

Extend GrpcHandlerAdapter and override only the callbacks you need.

GrpcChannel

GrpcChannel wraps the gRPC StreamObserver and provides methods for sending messages:

channel.uuid(); // Connection tracking ID
channel.write("Hello"); // Send text message
channel.write(bytes); // Send binary message
channel.write("/chat", "Hello"); // Send to specific topic
channel.isOpen(); // Check connection state
channel.resource(); // Associated AtmosphereResource
channel.close(); // Close connection

AtmosphereGrpcServer Builder

AtmosphereGrpcServer.builder()
 .framework(framework) // AtmosphereFramework instance (required)
 .port(9090) // Server port (default: 9090)
 .handler(new MyHandler()) // GrpcHandler (default: GrpcHandlerAdapter)
 .enableReflection(true) // gRPC server reflection (default: true)
 .interceptor(myServerInterceptor) // Add gRPC ServerInterceptors
 .build();

The server implements AutoCloseable — use try-with-resources for automatic cleanup.

Spring Boot Integration

The Spring Boot starter auto-configures a gRPC server alongside the servlet container when atmosphere-grpc is on the classpath.

1. Add dependencies

<dependency>
 <groupId>org.atmosphere</groupId>
 <artifactId>atmosphere-spring-boot-starter</artifactId>
 <version>4.0.4</version>
</dependency>
<dependency>
 <groupId>org.atmosphere</groupId>
 <artifactId>atmosphere-grpc</artifactId>
 <version>4.0.4</version>
</dependency>

2. Enable in properties

atmosphere:
 packages: com.example.chat
 grpc:
 enabled: true
 port: 9090
 enable-reflection: true

Configuration Properties

Property Default Description
atmosphere.grpc.enabled false Enable gRPC transport server
atmosphere.grpc.port 9090 gRPC server port
atmosphere.grpc.enable-reflection true Enable gRPC server reflection

3. Provide a custom GrpcHandler bean (optional)

@Bean
public GrpcHandler grpcHandler() {
 return new GrpcHandlerAdapter() {
 @Override
 public void onOpen(GrpcChannel channel) {
 log.info("gRPC client connected: {}", channel.uuid());
 }
 @Override
 public void onMessage(GrpcChannel channel, String message) {
 log.info("gRPC message: {}", message);
 }
 };
}

If no GrpcHandler bean is defined, a default GrpcHandlerAdapter is used.

The gRPC server starts and stops with the Spring lifecycle automatically.

Mixed Transport

With both the servlet container and gRPC server running, clients can connect over any transport — WebSocket, SSE, long-polling via HTTP, or gRPC via HTTP/2 — and they all share the same Broadcasters:

@ManagedService(path = "/chat")
public class Chat {
 @Message
 public String onMessage(String message) {
 // Broadcast reaches ALL clients — WebSocket, SSE, AND gRPC
 return message;
 }
}

Java Client (wAsync)

The Java client (wAsync) supports gRPC as a transport:

Client client = Client.newClient();
Request request = client.newRequestBuilder()
 .uri("grpc://localhost:9090/chat")
 .transport(Request.TRANSPORT.GRPC)
 .build();
Socket socket = client.create();
socket.on(Event.MESSAGE, msg -> System.out.println("Received: " + msg))
 .open(request);
socket.fire("Hello via gRPC!");

Sample

See the gRPC chat sample for a complete working example.

See Also

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /