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 .proto files 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