Advanced Spring Boot Microservices Backend
This repository is a multi module Spring Boot microservices template designed for a real world backend with:
- Service discovery
- Centralized configuration
- API gateway with routing and circuit breakers
- Domain services for user, inventory, and QR
- Kafka based event streaming and audit logging
- MySQL as primary database
It is intentionally written so that senior developers can dive straight into modules and architecture, while fresh developers can learn from the folder structure, naming and comments.
Core building blocks
-
Service Registry
- Eureka server that keeps a registry of all running services.
- Other services register themselves and discover each other using logical names (
user-service,inventory-service,qr-service,api-gateway,config-server).
-
Config Server
- Spring Cloud Config Server that reads configuration from a
config-repofolder (or Git repo). - Each service can fetch its configuration from here instead of hardcoding everything in its own jar.
- Spring Cloud Config Server that reads configuration from a
-
API Gateway
- Spring Cloud Gateway (reactive, WebFlux).
- Acts as the single entry point for the frontend.
- Routes HTTP requests to downstream services using service discovery (
lb://user-service, etc). - Adds cross cutting concerns:
- Circuit breakers with fallbacks
- Basic header manipulation (strip prefix, remove cookies, add trace IDs)
- Audit logging to Kafka
-
Domain Services
- user-service
Manages user accounts, basic profile data, and security related operations. - inventory-service
Manages items owned by users (belongs toownerUserId). Callsuser-serviceto validate user existence. - qr-service
Generates and decodes QR codes using ZXing, and can persist metadata.
- user-service
-
common-lib
- Shared DTOs, event classes, and basic utilities that are used by multiple services to avoid duplication.
-
Messaging and Audit
- Kafka is used as the message broker.
- Spring Cloud Stream is used to publish structured events:
AuditEventfrom API gateway toaudit-eventstopic.- Domain events (user, inventory, qr) can be published to their own topics.
- Other services may later subscribe to these topics to build analytics, notifications, etc.
-
Database
- MySQL is used as the primary relational store.
- For simplicity, both
user-serviceandinventory-servicecan point to the sameuserdbschema (or you can split later if needed). - QR service can also use MySQL for persistence.
At the top level:
advanced-microservices-backend/
├─ pom.xml # parent Maven pom
├─ README.md # this file
├─ common-lib/
├─ service-registry/
├─ config-server/
├─ api-gateway/
├─ user-service/
├─ inventory-service/
└─ qr-service/
Inside each service (for example user-service) you will see a layered structure:
user-service/src/main/java/com/example/userservice/
├─ domain/ # JPA entities, domain models
├─ repository/ # Spring Data JPA repositories
├─ service/ # business logic (Application services)
├─ web/ # controllers and DTOs (request/response)
├─ mapping/ # MapStruct mappers
├─ client/ # HTTP clients to other microservices
├─ messaging/ # event publishers / consumers (Kafka, etc)
└─ config/ # Spring configuration classes
This is a classic hexagonal / layered style:
- Controllers only deal with HTTP and DTOs.
- Services contain business rules.
- Repositories hide persistence details.
- Mappers convert between domain and DTOs.
- Frontend calls
http://localhost:8080(API gateway). - API Gateway uses routing rules to forward:
/api/users/**→lb://user-service/api/inventory/**→lb://inventory-service/api/qr/**→lb://qr-service
- The
lb://prefix means:- Lookup the service name in Eureka registry
- Load balance across instances if multiple are running.
If a downstream service is down or slow, the circuit breaker on the gateway triggers and:
- Returns a fallback JSON from
FallbackController - Optionally logs or sends metrics.
Example: inventory-service creates an item for a given user.
inventory-servicereceivesPOST /api/inventorywithownerUserId.InventoryServicecallsUserClient(a HTTP client) which targetsuser-servicevia service discovery.- If
user-servicereturns OK, the inventory item is saved. - If
user-serviceis down, Resilience4J circuit breaker can fall back (or throw custom exception).
Every HTTP request through gateway is audited:
- API gateway
WebFilterbuilds anAuditEventwith:- Trace ID
- Path, method
- Client IP
- Timestamp
- It uses
AuditPublisherandStreamBridgeto sendAuditEventto bindingaudit-out-0. audit-out-0is mapped (viaapplication.yml) to Kafka topicaudit-events.- Any downstream consumer service can subscribe to
audit-eventsfor monitoring or analytics.
You can extend the same pattern for domain events:
user-service→user-eventstopicinventory-service→inventory-eventstopicqr-service→qr-eventstopic
For a local developer setup you need:
-
Java JDK
- JDK 23 (or any version supported by your Spring Boot version).
-
MySQL
- Example configuration:
- Host:
localhost - Port:
3306 - Database:
userdb - User:
user - Password:
password
- Host:
- Make sure those values match each service
application.yml(or later the config-server properties).
- Example configuration:
-
Kafka + Zookeeper
-
You can use Docker for convenience, for example:
docker compose up -d # if you have a docker-compose fileor install Kafka locally and run:
# example, adjust to your installation bin/zookeeper-server-start.sh config/zookeeper.properties bin/kafka-server-start.sh config/server.properties
-
-
Config repo
- For now the services are still reading from local
application.ymlinside each module. - Later we will move those configurations to
config-repoand point config-server to it.
- For now the services are still reading from local
Recommended order:
-
Service registry
cd service-registry mvn spring-boot:run # Visit http://localhost:8761 to see the registry UI
-
Config server
cd config-server mvn spring-boot:run # Exposes config at http://localhost:8888
-
Infrastructure: MySQL + Kafka
- Make sure MySQL and Kafka are running.
-
Domain services
cd user-service mvn spring-boot:run cd inventory-service mvn spring-boot:run cd qr-service mvn spring-boot:run
-
API gateway
cd api-gateway mvn spring-boot:run # Gateway now listens on http://localhost:8080
Things you may care about:
- Version alignment
- Parent pom manages Spring Boot, Spring Cloud, Spring Cloud Stream, MapStruct, Lombok versions.
- Cross cutting concerns
- Centralized config via config-server (once enabled).
- Circuit breakers at gateway level.
- Kafka based audit events.
- Extensibility
- Add new microservices by:
- Creating a new module
- Registering with Eureka
- Adding a route in gateway
- Optionally wiring Kafka producers / consumers for events.
- Add new microservices by:
Key ideas to learn from this template:
-
Separation of concerns
- Controllers handle HTTP.
- Services handle business logic.
- Repositories handle DB.
- Mappers convert between domain and DTOs.
-
Why use an API gateway?
- Frontend talks to a single URL.
- We can centralize security, logging, and routing logic.
-
Why use a service registry?
- We do not hardcode
http://localhost:8081for user-service. - We use service name (
lb://user-service) and let Eureka do the lookup.
- We do not hardcode
-
Why message queue / Kafka?
- HTTP is good for request reply.
- Kafka is good for event driven patterns (audit, analytics, async workflows).
-
How config will be centralized (later step)
- Instead of each service having its own
application.yml, we can define e.g.user-service.propertiesinventory-service.properties
- Config server serves them, and services load them from there. This makes configuration changes easier in production.
- Instead of each service having its own
Each module has its own README.md with:
- Purpose
- Package layout
- Important configuration
- How it communicates with others
- Examples of typical flows
See:
service-registry/README.mdconfig-server/README.mdapi-gateway/README.mduser-service/README.mdinventory-service/README.mdqr-service/README.md
- http://localhost:8080/auth/v3/api-docs
- http://localhost:8080/users/v3/api-docs
- http://localhost:8080/inventory/v3/api-docs
- http://localhost:8080/qr/v3/api-docs
Your services are exposed through Spring Cloud Gateway routes. The StripPrefix filter removes N path segments before forwarding downstream. :contentReference[oaicite:0]{index=0}
Use either the /api/... style or the short style:
http://localhost:8080/api/auth/<endpoint>http://localhost:8080/auth/<endpoint>
http://localhost:8080/api/users/<endpoint>http://localhost:8080/users/<endpoint>
http://localhost:8080/api/inventory/<endpoint>http://localhost:8080/inventory/<endpoint>
http://localhost:8080/api/qr/<endpoint>http://localhost:8080/qr/<endpoint>
Replace
<endpoint>with the actual controller path (see Swagger below).
http://localhost:8080/swagger-ui.htmlhttp://localhost:8080/swagger-ui/index.html
Springdoc commonly serves OpenAPI JSON at /v3/api-docs and Swagger UI via /swagger-ui... when enabled. :contentReference[oaicite:1]{index=1}
http://localhost:8080/auth/v3/api-docshttp://localhost:8080/users/v3/api-docshttp://localhost:8080/inventory/v3/api-docshttp://localhost:8080/qr/v3/api-docs
http://localhost:8080/v3/api-docs
Your gateway can aggregate multiple downstream OpenAPI specs using
springdoc.swagger-ui.urls. :contentReference[oaicite:2]{index=2}
Open:
http://localhost:8080/swagger-ui.html
Then pick each service in the dropdown to see all endpoints + request/response models.