Skip to content

Repository files navigation

Spring Boot Microservices Template

JavaSpring BootSpring CloudKafkaRedisDockerKubernetesLicense

A production-ready Spring Boot 3 microservices template. Includes service discovery, centralized configuration, API gateway with JWT filtering, Redis caching, Kafka event streaming, circuit breaking, and full Docker orchestration with proper health checks. Built to be cloned, understood, and extended.


Table of Contents


Architecture

 +-----------------------+
| Client Apps |
+-----------+-----------+
|
v
+-----------+-----------+
| API Gateway |
| JWT Filter :8080 |
+-----------+-----------+
|
+-----------+----------+-----------+-----------+
| | | |
v v v v
+------+----+ +----+------+ +------+----+ +----+------+
| Auth | | User | | Mail | | Notif. |
| Service | | Service | | Service | | Service |
| :8083 | | :8081 | | :8084 | | :8082 |
+------+----+ +----+------+ +------+----+ +----+------+
| | | |
| +----+----+ | |
| | Redis | | |
| | :6379 | | |
| +---------+ | |
| | | |
| +----+----+ | |
+----->| |<----------------+-----------+
| Kafka |
| :29092 |
| |
+----+----+
|
+-----------+-----------+
| |
v v
+----------+----------+ +---------+---------+
| PostgreSQL | | Zookeeper |
| :5432 | | :2181 |
+---------------------+ +-------------------+
+-----------------------+ +----------------------+
| Eureka Server | | Config Server |
| :8761 | | :8888 |
+-----------------------+ +----------------------+
All services register with Eureka on startup.
All services fetch config from Config Server on startup.

Services

ServicePortRole
API Gateway8080Single entry point. JWT validation, request routing, load balancing
Eureka Server8761Service registry. All services register and discover each other here
Config Server8888Centralized configuration. Serves per-service properties at startup
User Service8081User management. PostgreSQL + Redis cache + Kafka producer
Auth Service8083Authentication. JWT issuance and validation
Mail Service8084Email delivery. Kafka consumer — sends emails on events
Notification Service8082Event processing. Kafka consumer for user lifecycle events
PostgreSQL2500Primary relational database
Redis6379Distributed cache for user lookups and session data
Kafka19092Event streaming between services
Zookeeper2181Kafka cluster coordination

Technology Stack

CategoryTechnology
CoreJava 21, Spring Boot 3.5.7, Spring Cloud 2025.0.0
GatewaySpring Cloud Gateway
DiscoveryNetflix Eureka
ConfigurationSpring Cloud Config Server
DatabasePostgreSQL 15, Spring Data JPA, Hibernate
CachingRedis 7.x, Spring Cache, JSON serialization
MessagingApache Kafka 7.5.0, Spring Kafka
SecuritySpring Security, JWT (jjwt 0.12.5)
ResilienceResilience4j Circuit Breaker, Spring Retry
MonitoringSpring Boot Actuator, Loki, Promtail, Grafana
Load TestingGatling 3.10.5
ContainerizationDocker, Docker Compose
OrchestrationKubernetes (Deployments, StatefulSets, HPA)

Core Workflows

Request Lifecycle

 Client Gateway Service Database
| | | |
| HTTP Request | | |
|--------------------->| | |
| | | |
| | Validate JWT | |
| |----+ | |
| | | | |
| |<---+ | |
| | | |
| | Route via lb:// | |
| |------------------->| |
| | | |
| | | Query / Write |
| | |------------------->|
| | | |
| | | Result |
| | |<-------------------|
| | | |
| | Response | |
| |<-------------------| |
| | | |
| HTTP Response | | |
|<---------------------| | |

Redis Cache Flow

 Service Redis PostgreSQL
| | |
| GET user::{id} | |
|---------------------->| |
| | |
| [Cache Hit] | |
|<----------------------| |
| Return cached user | |
| | |
| [Cache Miss] | |
|<----------------------| |
| | |
| SELECT * FROM users | |
|---------------------------------------------->|
| | |
| User result | |
|<----------------------------------------------|
| | |
| SET user::{id} TTL | |
|---------------------->| |
| | |
| Return user | |
|<--- | |

Kafka Event Flow

 User Service Kafka Broker Mail Service SMTP Server
| | | |
| Publish USER_CREATED | | |
|---------------------->| | |
| | | |
| | Consume EVENT | |
| |--------------------->| |
| | | |
| | | Send Email |
| | |------------------>|
| | | |
| | | 250 OK |
| | |<------------------|

Authentication Flow

 Client Gateway Auth Service User Service
| | | |
| POST /auth/login | | |
|----------------->| | |
| | Forward | |
| |------------------>| |
| | | Fetch user |
| | |------------------>|
| | | |
| | | User details |
| | |<------------------|
| | | |
| | | Validate password |
| | |----+ |
| | | | |
| | |<---+ |
| | | |
| | JWT Token | |
| |<------------------| |
| | | |
| 200 OK + JWT | | |
|<-----------------| | |

Quick Start

Prerequisites: Docker, Docker Compose

# Clone
git clone https://github.com/Goal651/springboot_microservice
cd springboot_microservice
# Setup environment
cp .env.example .env
# Edit .env with your values# Start all services
docker compose -f compose.dev.yml up --build

Services take approximately 3-4 minutes to fully start. Check status:

# All containers and health status
docker compose -f compose.dev.yml ps
# Follow logs
docker compose -f compose.dev.yml logs -f
# Test gateway
curl http://localhost:8080/actuator/health
# Eureka dashboard
open http://localhost:8761

Performance

Load tested with Gatling — 50 concurrent users, 30 second ramp, 6 concurrent scenarios running simultaneously against the full stack through the API gateway.

MetricResult
Total Requests466
Success Rate100%
Mean Response Time10ms
50th Percentile5ms
95th Percentile46ms
99th Percentile72ms
Max Response Time150ms
Throughput12.9 req/sec

GET /users/{id} achieved 6ms p95 — Redis cache serving repeated lookups without hitting PostgreSQL.

Gatling OverviewGatling StatsActive Users

Run load tests yourself:

cd load-tests
mvn gatling:test -DbaseUrl=http://localhost:8080 -Djwt=YOUR_JWT_TOKEN
# Higher load
mvn gatling:test -DbaseUrl=http://localhost:8080 -Djwt=YOUR_JWT_TOKEN -Dusers=200 -Dramp=60

Configuration

All service configuration is managed centrally by Config Server.

configServer/src/main/resources/
├── application.properties <- Config Server own config
└── configs/
├── application.properties <- Shared by ALL services
├── user-service.properties
├── auth-service.properties
├── mail-service.properties
├── gateway.properties
└── eureka.properties

Each microservice's own application.properties contains only two lines:

spring.application.name=user-service
spring.config.import=optional:configserver:http://config-server:8888

Everything else — ports, DB URLs, Kafka addresses, Redis config — lives in the Config Server. Secrets are passed via .env into Docker Compose environment variables, then referenced as ${VAR_NAME} inside config files.

To refresh config at runtime without restarting:

curl -X POST http://localhost:8081/actuator/refresh

Kafka Topics

TopicProducerConsumersEvents
user-eventsuser-servicenotification-serviceUSER_CREATED, USER_UPDATED, USER_DELETED
auth-eventsauth-servicemail-serviceUSER_REGISTERED, PASSWORD_RESET
mail-eventsany servicemail-serviceEMAIL_REQUESTED

Internal broker (Docker): kafka:29092 External broker (host machine): localhost:19092


Redis Caching

Cache keys follow the pattern entity::{id}. TTL is configured per entity type in configs/user-service.properties.

spring.data.redis.host=redis
spring.data.redis.port=6379
spring.cache.type=redis
spring.cache.redis.time-to-live=600000

Check Redis directly:

docker exec -it redis redis-cli
> KEYS *> GET user::1
> TTL user::1

Health Checks

All services implement Docker health checks. Startup order is enforced via condition: service_healthy.

ServiceHealth Check
Spring servicesGET /actuator/health
PostgreSQLpg_isready
Kafkakafka-broker-api-versions --bootstrap-server localhost:29092
Zookeeperecho srvr | nc localhost 2181 | grep Mode: standalone
Redisredis-cli ping

Startup order: zookeeperkafkadbeurekaconfig-serverservices


Centralized Logging

Logs are centralized with Promtail → Loki → Grafana.

  • Promtail tails Docker container logs and forwards them to Loki.
  • Loki stores and indexes logs.
  • Grafana provides querying and visualization.

Start the stack (logging services are already included in compose):

docker compose -f compose.dev.yml up --build -d

Access:

  • Grafana: http://localhost:3000
  • Loki: http://localhost:3100

Default Grafana credentials are admin/admin (override in .env with GRAFANA_ADMIN_USER and GRAFANA_ADMIN_PASSWORD).

Example LogQL queries in Grafana Explore:

{compose_service="gateway"}
{compose_project="springboot_microservice"}

Adding a New Service

1. Create Spring Boot project with dependencies: web, actuator, eureka-client, spring-cloud-config

2. Set application.properties to two lines only:

spring.application.name=your-service
spring.config.import=optional:configserver:http://config-server:8888

3. Add config file at configServer/src/main/resources/configs/your-service.properties:

server.port=8085
eureka.client.service-url.defaultZone=http://eureka:8761/eureka

4. Add route to configs/gateway.properties:

spring.cloud.gateway.routes[N].id=your-service
spring.cloud.gateway.routes[N].uri=lb://your-service
spring.cloud.gateway.routes[N].predicates[0]=Path=/your-path/**

5. Add to compose.dev.yml:

your-service:
build:
context: ./yourServicedockerfile: Dockerfile.devcontainer_name: your-servicedepends_on:
eureka:
condition: service_healthyconfig-server:
condition: service_healthyhealthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8085/actuator/health || exit 1"]interval: 10stimeout: 5sretries: 5start_period: 40snetworks:
- micro-netports:
- "8085:8085"

Kubernetes

Full Kubernetes manifests are available in the k8s/ directory.

# Create namespace
kubectl apply -f k8s/namespace.yaml
# Apply secrets and config
kubectl apply -f k8s/app-secrets.yaml
kubectl apply -f k8s/app-config.yaml
# Deploy infrastructure
kubectl apply -f k8s/infrastructure/ --recursive
# Deploy services
kubectl apply -f k8s/config-server/
kubectl apply -f k8s/eureka/
kubectl apply -f k8s/gateway/
kubectl apply -f k8s/user-service/
kubectl apply -f k8s/auth-service/
kubectl apply -f k8s/mail-service/

Each service has: Deployment, Service, HorizontalPodAutoscaler, and ConfigMap. Infrastructure (PostgreSQL, Redis, Kafka, Zookeeper) uses StatefulSet for stable network identity and persistent storage.


Common Issues

Service can't reach Kafka Use kafka:29092 inside Docker network. Use localhost:19092 from host machine. Never use port 9092 directly.

Service can't reach database Use db:5432 inside Docker network. Use localhost:2500 from host machine.

Config Server not found on startup Eureka must be healthy before Config Server starts. Config Server must be healthy before any service that imports from it. Check depends_on conditions in compose.dev.yml.

Service starts but stays unhealthy Check if spring-boot-starter-web is in pom.xml. Without it, Spring Boot runs in non-web mode and Actuator has no HTTP server to bind to.

Kafka deserialization errors Ensure producer and consumer DTOs match. Disable type headers:

spring.kafka.producer.properties.spring.json.add.type.headers=false
spring.kafka.consumer.properties.spring.json.use.type.headers=false

Port mapping confusion Kafka container listens on 29092 internally. Host port 19092 maps to container port 29092. Compose mapping is "19092:29092".


Port Reference

ServiceHost PortContainer Port
API Gateway80808080
User Service80818081
Notification Service80828082
Auth Service80838083
Mail Service80848084
Eureka Server87618761
Config Server88888888
PostgreSQL25005432
Redis63796379
Kafka1909229092
Zookeeper21812181
Grafana30003000
Loki31003100

Built by Wilson (wigothehacker) — portfolio at goal651.vercel.app

About

Production-ready Spring Boot 3 + Kafka + Docker microservices template with Eureka, API Gateway, and Circuit Breaker

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages