Architecture

A platform layer that keeps service architecture explicit and infrastructure behavior consistent.

Spring Middleware sits between business services and infrastructure. It standardizes communication, discovery, tracing, GraphQL federation, messaging, and infrastructure integration while keeping each service focused on domain logic.

Platform layering
Application business logic
Spring Middleware platform layer
Spring Boot / infrastructure / transport
Design goals
  • Centralize cross-cutting concerns without hiding architecture behind magic.
  • Keep services autonomous and business-focused.
  • Standardize behavior across communication, errors, tracing, and infrastructure integration.

Control plane and data plane

Spring Middleware uses a registry-driven architecture with a clear separation between topology control and runtime service execution.

Control plane

The Registry Service acts as the control plane. It maintains service topology, registered REST metadata, GraphQL schema locations, node endpoints, and health-related cleanup.

Service topology API metadata Schema locations Node health

Data plane

Application services expose APIs, call each other through declarative clients, participate in the same tracing and error model, and use infrastructure modules for persistence, caching, and messaging.

Declarative HTTP GraphQL federation Redis / Mongo / JPA Kafka / RabbitMQ

High-level topology

Services register themselves, expose metadata to the control plane, and consume other services through registry-resolved clients.

Registry Service

Tracks clusters, nodes, REST resources, GraphQL schemas, and platform metadata required for runtime resolution.

Service A

@Register resources, GraphQL schemas, middleware clients, tracing, and infrastructure modules.

Service B

Registers itself in the control plane and consumes remote services through registry-driven resolution.

Service C

Participates in the same topology, error model, tracing propagation, and platform conventions.

Core concepts

The platform is built around a few explicit concepts that define topology, registration, and service communication.

Cluster and node

A cluster is the logical service identity, such as product-service or catalog-service. A node is a concrete running instance of that cluster, such as a pod, container, or VM.

The Registry tracks both the logical service boundary and the concrete node endpoints available at runtime.

Registry

The Registry is the control-plane component that stores service topology, REST metadata, GraphQL schema locations, and node health information.

It exposes structures such as RegistryEntry and SchemaLocation so the platform can resolve topology and federation metadata explicitly.

Resources and schemas

A resource is a registered REST endpoint, typically implemented in a Spring @RestController and annotated with @Register. A schema is a GraphQL schema registered for later composition and federation.

Declarative clients

@MiddlewareClient defines a declarative HTTP contract against another service. The platform resolves service identity to concrete endpoints through the Registry, applies node selection, and propagates context and errors consistently.

Service bootstrapping

Startup is based on annotation scanning, explicit registration, and periodic reconciliation with the control plane.

1

Application startup

Spring Boot initializes the service and creates the application context.

2

Annotation scanning

Spring Middleware scans for annotations such as @Register and @MiddlewareClient.

3

Metadata registration

REST resources, GraphQL schema information, and node identity are registered in the Registry.

4

Runtime reconciliation

A scheduler periodically verifies consistency and restores missing topology or metadata when necessary.

Control plane convergence and self-healing

The Registry is not treated as a permanently correct source of truth. Services continuously reconcile their presence and metadata so the platform converges back to the real cluster state after failures.

Destroying registry state does not permanently break the system. Restarting nodes reconstructs topology, restores metadata, and recreates node-scoped infrastructure without manual intervention.

What services verify

  • Node endpoint presence in the Registry
  • REST resource registration
  • GraphQL schema node registration
  • Required messaging infrastructure existence

What the platform restores

  • Missing REST metadata
  • Missing GraphQL schema entries
  • Lost node endpoints
  • Node-scoped queues and bindings

Failure handling

When nodes disappear, the Registry removes stale endpoints, messaging resources tied to dead nodes are cleaned up, and topology remains free of orphaned state.

Runtime impact

Clients fail fast when no nodes are available and resume normal operation automatically when capacity returns. The system converges instead of drifting into a broken state.

Service communication flow

Runtime calls are routed through declarative interfaces, registry lookup, node selection, and standardized request/response handling.

1

Application code invokes a declarative client

A method is called on an interface annotated with @MiddlewareClient.

2

Cluster resolution

The target service identity is resolved from the client metadata.

3

Registry lookup and node selection

Available nodes are queried from the Registry and a node selection strategy resolves the actual HTTP endpoint.

4

Request execution and propagation

The request is sent through WebClient with propagated headers such as X-Request-ID and X-Span-ID.

5

Typed response and unified failures

Responses are mapped to the target method signature and remote failures are normalized into a structured error model.

Error and tracing model

Spring Middleware defines a consistent error structure and lightweight cross-service tracing without requiring a full tracing stack.

Structured errors

The platform standardizes failure handling through types such as ServiceException, ErrorDescriptor, ErrorMessage, and RemoteServerException, together with centralized @RestControllerAdvice.

{ "statusCode": 404, "statusMessage": "Not Found", "code": "PRODUCT:NOT_FOUND", "message": "Product not found", "extensions": {} }

Lightweight tracing

Every request participates in correlation through X-Request-ID and X-Span-ID. The goal is explicit observability and easier log correlation across services, including GraphQL requests and remote HTTP calls.

Module architecture

Spring Middleware is published as a multi-module ecosystem managed through a BOM and organized by platform concern.

Core

commons, api, app, model-api, model-core, view-api, view-core

Data

mongo-*, jpa-*, redis-*, cache

Messaging

rabbitmq, kafka and platform-aligned messaging support

Platform

registry-*, graphql and control-plane related modules

Typical infrastructure structure

module ├─ api ├─ core └─ core-react (optional)

Typical dependency flow

boot ↓ core ↓ api

Repository and consumption model

The repository is structured as a Maven multi-module project. Consumers import the BOM and select the modules they need. Contributors work inside the implementation tree.

For consumers

Depend on the BOM and the required modules from Maven Central. This keeps versions aligned across the platform and avoids per-service dependency drift.

For contributors

Work inside the parent multi-module project and build from the repository root. The architecture is modular, but intentionally composed as a platform rather than a set of disconnected utilities.

Read the platform through its building blocks

Continue with GraphQL federation, messaging, modules, or the getting started documentation to see how the architecture maps to real runtime behavior and reusable modules.

Open documentation