Skip to content

LordMaduz/Realtime-Event-Processing-With-Reactive-gRPC

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Reactive gRPC with Spring Boot

Production-ready reactive gRPC implementation with Spring WebFlux, Protocol Buffers, and JWT authentication for high-performance real-time request processing.

Overview

A fully reactive microservices communication system built with gRPC and Spring Boot. Features non-blocking request/response patterns, type-safe Protocol Buffers serialization, OAuth2 JWT authentication, and reactive streaming for efficient inter-service communication.

Key Features:

  • Fully reactive gRPC with Project Reactor
  • Protocol Buffers for efficient serialization
  • JWT Bearer token authentication
  • Non-blocking request/response patterns
  • Type-safe service contracts
  • Spring Boot gRPC integration
  • Client-side load balancing ready
  • OpenAPI documentation (client)

Architecture

Mermaid Chart - Create complex, visual diagrams with text -2025-10-14-153026

Request Flow

Mermaid Chart - Create complex, visual diagrams with text -2025-10-14-152834

Tech Stack

Category Technologies
Core Java 21, Spring Boot 3.2.2
Reactive Spring WebFlux, Project Reactor
RPC gRPC 1.60.0, Reactor gRPC 1.2.4
Serialization Protocol Buffers 3.25.0
Security OAuth2 Resource Server, JWT
Framework Spring Boot gRPC Starter 2.15.0

Getting Started

Prerequisites

Java 21+
Maven 3.8+
Protocol Buffers Compiler (protoc)

Installation

1. Build Common Library

cd reactive-gRPC-common
mvn clean install

This generates:

  • gRPC service stubs
  • Reactive gRPC stubs
  • Protocol Buffers Java classes

2. Build gRPC Server

cd reactive-gRPC-server
mvn clean install

3. Build gRPC Client

cd reactive-gRPC-client
mvn clean install

Configuration

Server Configuration

application.yaml:

grpc:
  server:
    port: 8000

server:
  port: 8080

spring:
  application:
    name: reactive-gRPC-Server
  security:
    oauth2:
      resourceserver:
        jwt:
          key-value: classpath:rsa-public.key

Client Configuration

application.properties:

server.port=8085
grpc.server.port=9090

Running the Application

1. Start gRPC Server

cd reactive-gRPC-server
mvn spring-boot:run

Server starts on:

  • gRPC: localhost:8000
  • HTTP: localhost:8080

2. Start gRPC Client

cd reactive-gRPC-client
mvn spring-boot:run

Client starts on http://localhost:8085

Swagger UI: http://localhost:8085/webjars/swagger-ui/index.html

API Usage

Save Inventory (via gRPC)

Request:

curl -X GET http://localhost:8085

What Happens:

  1. REST API calls gRPC client
  2. Client creates Protobuf message
  3. Sends via gRPC to server
  4. Server authenticates JWT token
  5. Processes request reactively
  6. Returns Protobuf response
  7. Client converts to JSON

Response:

{
  "inventoryId": "550e8400-e29b-41d4-a716-446655440000",
  "name": "NEAL"
}

Key Features

Protocol Buffers Service Definition

InventoryManager.proto:

syntax = "proto3";
option java_package = "com.reactive.grpc";
option java_outer_classname = "InventoryManagerProto";

import "Inventory.proto";
import "InventoryRequest.proto";

service InventoryManagerService {
  rpc saveInventory(Inventory) returns (Inventory);
  rpc findInventoryById(InventoryRequest) returns (Inventory);
}

Inventory.proto:

syntax = "proto3";
option java_package = "com.reactive.grpc";
option java_outer_classname = "InventoryProto";

message Inventory {
  string inventoryId = 1;
  string name = 2;
}

Reactive gRPC Server

@GrpcService
@RequiredArgsConstructor
public class InventoryManagerService 
        extends ReactorInventoryManagerServiceGrpc.InventoryManagerServiceImplBase {

    private final InventoryProtoMapper inventoryProtoMapper;

    @Override
    public Mono saveInventory(
            Mono request) {
        
        return request
            .map(inventoryProtoMapper::fromProto)
            .doOnNext(inventory -> log.info("Processing: {}", inventory))
            .map(inventoryProtoMapper::toProto)
            .doOnError(error -> log.error("Error: {}", error.getMessage()))
            .onErrorResume(Mono::error);
    }
}

Reactive gRPC Client

@Component
@RequiredArgsConstructor
public class InventoryManagerGrpcClient implements InventoryManagerClient {

    private final ReactorInventoryManagerServiceGrpc.ReactorInventoryManagerServiceStub stub;
    private final InventoryProtoMapper inventoryProtoMapper;

    @Override
    public Mono saveInventory() {
        Inventory inventory = Inventory.builder()
            .inventoryId(UUID.randomUUID().toString())
            .name("NEAL")
            .build();

        Mono protoMono = 
            stub.saveInventory(Mono.just(inventoryProtoMapper.toProto(inventory)));

        return protoMono.map(inventoryProtoMapper::fromProto);
    }
}

gRPC Channel Configuration

@Configuration
public class GrpcConfiguration {

    @Bean
    public ReactorInventoryManagerServiceGrpc.ReactorInventoryManagerServiceStub 
            inventoryManagerServiceStub() {
        
        ManagedChannel channel = ManagedChannelBuilder
            .forAddress("localhost", 8000)
            .usePlaintext()
            .build();

        return ReactorInventoryManagerServiceGrpc.newReactorStub(channel);
    }
}

JWT Security Configuration

@Configuration
public class SecurityConfiguration {

    @Value("${spring.security.oauth2.resourceserver.jwt.key-value}")
    RSAPublicKey publicKey;

    @Bean
    public AuthenticationManager authenticationManager() {
        List providers = new ArrayList<>();
        providers.add(new JwtAuthenticationProvider(jwtDecoder()));
        return new ProviderManager(providers);
    }

    @Bean
    public GrpcAuthenticationReader authenticationReader() {
        return new BearerAuthenticationReader(BearerTokenAuthenticationToken::new);
    }

    @Bean
    JwtDecoder jwtDecoder() {
        return NimbusJwtDecoder.withPublicKey(publicKey).build();
    }
}

Protobuf Mapper

@Component
public class InventoryProtoMapper 
        implements ProtobufMapper {

    @Override
    public InventoryProto.Inventory toProto(Inventory inventory) {
        return InventoryProto.Inventory.newBuilder()
            .setInventoryId(inventory.getInventoryId())
            .setName(inventory.getName())
            .build();
    }

    @Override
    public Inventory fromProto(InventoryProto.Inventory proto) {
        return Inventory.builder()
            .inventoryId(proto.getInventoryId())
            .name(proto.getName())
            .build();
    }
}

Authentication

JWT Token Format

The server expects Bearer token in Authorization header:

Authorization: Bearer <JWT_TOKEN>

Sample Token (from Bearer-token.txt):

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJzdWJqZWN0IiwiaWF0IjoxNTE2MjM5MDIyLCJzY29wZSI6Im1lc3NhZ2U6cmVhZCJ9.bsRCpUEaiWnzX4OqNxTBqwUD4vxxtPp-CHKTw7XcrglrvZ2lvYXaiZZbCp-hcPhuzMEzEAFuH6s4GZZOWVIX-wT47GdTz9cfA-Z4QPjS2RxePKphFXgBI3jHEpQo94Qya2fJdV4LvgBmA1uM_RTnYY1UbmeYuHKnXrZoGyV8QQQ

RSA Key Pair

Server uses RSA public key for JWT validation:

rsa-public.key:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdlatRjRjogo3WojgGHFHYLugd
UWAY9iR3fy4arWNA1KoS8kVw33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQs
HUfQrSDv+MuSUMAe8jzKE4qW+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5D
o2kQ+X5xK9cipRgEKwIDAQAB
-----END PUBLIC KEY-----

Learn More

For a comprehensive guide on building reactive gRPC applications with Spring Boot:

Complete Implementation Tutorial

Reactive Real-Time Request Processing with Reactive gRPC and Spring WebFlux

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages