On this page
gRPC Java Basics
gRPC is a high-performance RPC framework using Protocol Buffers for serialization and HTTP/2 for transport. It supports unary, server streaming, client streaming, and bidirectional streaming.
Setup
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.60.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.60.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.60.0</version>
</dependency>
Protobuf Maven plugin generates Java classes from .proto files.
Service Definition
src/main/proto/user.proto:
syntax = "proto3";
option java_package = "com.example.grpc";
option java_multiple_files = true;
service UserService {
rpc GetUser (GetUserRequest) returns (UserResponse);
rpc ListUsers (ListUsersRequest) returns (stream UserResponse);
rpc CreateUsers (stream CreateUserRequest) returns (CreateUsersResponse);
}
message GetUserRequest {
int64 id = 1;
}
message UserResponse {
int64 id = 1;
string name = 2;
string email = 3;
}
message ListUsersRequest {
int32 page = 1;
int32 size = 2;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message CreateUsersResponse {
int32 count = 1;
}
Server Implementation
public class UserServiceImpl extends UserServiceGrpc.UserServiceImplBase {
@Override
public void getUser(GetUserRequest request, StreamObserver<UserResponse> responseObserver) {
User user = userRepository.findById(request.getId()).orElseThrow();
UserResponse response = UserResponse.newBuilder()
.setId(user.getId())
.setName(user.getName())
.setEmail(user.getEmail())
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
@Override
public void listUsers(ListUsersRequest request, StreamObserver<UserResponse> responseObserver) {
userRepository.findAll(PageRequest.of(request.getPage(), request.getSize()))
.forEach(user -> {
responseObserver.onNext(toResponse(user));
});
responseObserver.onCompleted();
}
}
Server Startup
Server server = ServerBuilder.forPort(9090)
.addService(new UserServiceImpl())
.build()
.start();
server.awaitTermination();
Client
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 9090)
.usePlaintext()
.build();
UserServiceGrpc.UserServiceBlockingStub stub = UserServiceGrpc.newBlockingStub(channel);
UserResponse user = stub.getUser(GetUserRequest.newBuilder().setId(1).build());
// Server streaming
Iterator<UserResponse> users = stub.listUsers(
ListUsersRequest.newBuilder().setPage(0).setSize(20).build());
users.forEachRemaining(u -> System.out.println(u.getName()));
channel.shutdown();
Spring Boot Integration
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.15.0.RELEASE</version>
</dependency>
@GrpcService
public class UserGrpcService extends UserServiceGrpc.UserServiceImplBase {
@Override
public void getUser(GetUserRequest request, StreamObserver<UserResponse> observer) {
// implementation
}
}
gRPC vs REST
| Feature | gRPC | REST |
|---|---|---|
| Protocol | HTTP/2 + Protobuf | HTTP/1.1 + JSON |
| Performance | 5-10x faster | Baseline |
| Streaming | Built-in | SSE/WebSocket |
| Browser | Requires grpc-web | Native |
| Code generation | Required (.proto) | Optional (OpenAPI) |
| Best for | Service-to-service | Public APIs, browsers |
Best Practices
- Define
.protofiles as the contract — version them carefully - Use streaming for large datasets instead of pagination over unary calls
- Set deadlines on client calls:
stub.withDeadlineAfter(5, SECONDS) - Use TLS in production — never
usePlaintext() - Combine gRPC for internal communication with REST gateway for external clients