let’s put the Java Microservices Project Architecture together in a way that shows the structure of all projects, their roles, and how they connect.
1️⃣ High-Level Architecture Overview
2️⃣ Project Structure in Workspace
You would usually have multiple Spring Boot projects, one for each component:
3️⃣ Responsibilities of Each Project
1. API Gateway
Purpose: Single entry point for all clients.
Tasks:
Route requests to respective microservices.
Apply authentication (JWT/OAuth2).
Load balancing with Eureka.
Tech: Spring Cloud Gateway, Spring Security.
2. Service Registry (Eureka)
Purpose: Service discovery and registration.
Tasks:
Each service registers here with name + port.
API Gateway & services fetch other services’ locations dynamically.
3. Config Server
Purpose: Central config management.
Tasks:
Stores all application.properties in Git or local folder.
Pushes updates to services without restart.
4. User Service
Purpose: Manages users, authentication, profile.
Communication: REST API → Order Service.
Database: MS SQL/PostgreSQL.
5. Order Service
Purpose: Handles orders & cart operations.
Communication: REST API → Payment Service.
Database: MySQL/MongoDB.
6. Payment Service
Purpose: Processes payments, communicates with gateways.
Communication: Kafka event consumption from Order Service.
Database: PostgreSQL.
4️⃣ Communication Flow
Client → API Gateway → Routes request to target microservice.
Microservices discover each other via Eureka.
Configurations loaded from Config Server.
Async operations handled via Kafka.
Each service uses its own DB (no sharing).
5️⃣ Deployment
Local Dev: Run each service on different port.
Cloud: Dockerize each service → Deploy to Kubernetes.
CI/CD: GitHub Actions, Jenkins pipelines.
Java Microservices — Ready-to-Run Architecture Blueprint
A complete, minimal, ready-to-run blueprint with project layout, sample code, configuration, Docker/Docker Compose, and run instructions for a microservices system: Eureka (Service Registry), Config Server, API Gateway, User Service, Order Service, Payment Service + Kafka and MySQL. Meant for local development and easy transition to Docker/Kubernetes.
Overview
This blueprint shows how to structure multiple Spring Boot projects as independent microservices, how they discover each other (Eureka), share configuration (Config Server), expose a single entry point (API Gateway), communicate synchronously (Feign/WebClient/REST) and asynchronously (Kafka), and how to containerize them with Docker + Docker Compose for local testing.
Projects included:
service-registry(Eureka)config-server(Spring Cloud Config)api-gateway(Spring Cloud Gateway)user-service(business service)order-service(business service) — uses Feign to calluser-servicepayment-service(business service) — consumes Kafka events fromorder-service
Prerequisites
Java 17+ or 21 (adjust
java.versionaccordingly)Maven 3.6+
Docker & Docker Compose (for running containers)
Optional: IntelliJ / VSCode
Parent pom.xml (optional)
Use Spring Boot 3.x and Spring Cloud compatible release for best support.
1) service-registry (Eureka)
Purpose: Service discovery.
pom.xml (important deps)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>Main class
@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistryApplication {
public static void main(String[] args) { SpringApplication.run(ServiceRegistryApplication.class, args); }
}application.yml
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
server:
enable-self-preservation: false
spring:
application:
name: service-registry2) config-server
Purpose: Centralized configuration (backed by local config folder or Git).
pom.xml deps (key)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>Main class
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication { public static void main(String[] args){ SpringApplication.run(ConfigServerApplication.class,args);} }application.yml
server:
port: 8888
spring:
cloud:
config:
server:
native:
search-locations: classpath:/config, file:./config
eureka:
client:
enabled: falseConfig files
Place service property files in
config/(or Git). Example:user-service.yml,order-service.ymletc.
Example config/user-service.yml:
spring:
datasource:
url: jdbc:mysql://mysql:3306/userdb?createDatabaseIfNotExist=true
username: user
password: pass3) api-gateway
Purpose: Routing, authentication, rate-limiting (optional)
pom.xml deps (key)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>application.yml
server:
port: 8080
spring:
application:
name: api-gateway
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/users/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/orders/**Main class is plain @SpringBootApplication.
4) user-service
Purpose: User management & authentication.
pom.xml deps (important)
<dependency>spring-boot-starter-web</dependency>
<dependency>spring-boot-starter-data-jpa</dependency>
<dependency>mysql-connector-java</dependency>
<dependency>spring-cloud-starter-netflix-eureka-client</dependency>Application
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication { public static void main(String[] args){ SpringApplication.run(UserServiceApplication.class,args);} }application.yml (uses config server)
spring:
application:
name: user-service
cloud:
config:
uri: http://localhost:8888
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8081Simple entity & repo
@Entity
public class User {
@Id @GeneratedValue private Long id;
private String username;
private String role;
// getters/setters
}
public interface UserRepository extends JpaRepository<User, Long> {}Controller
@RestController
@RequestMapping("/users")
public class UserController {
private final UserRepository repo;
public UserController(UserRepository r){this.repo=r;}
@GetMapping("/{id}")
public ResponseEntity<User> get(@PathVariable Long id){
return repo.findById(id).map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());
}
}5) order-service
Purpose: Orders; calls user-service via Feign and publishes events to Kafka.
pom.xml deps (important)
<dependency>spring-boot-starter-web</dependency>
<dependency>spring-boot-starter-data-jpa</dependency>
<dependency>org.springframework.cloud:spring-cloud-starter-openfeign</dependency>
<dependency>org.springframework.kafka:spring-kafka</dependency>
<dependency>spring-cloud-starter-netflix-eureka-client</dependency>Main class
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class OrderServiceApplication{ public static void main(String[] args){ SpringApplication.run(OrderServiceApplication.class,args);} }Feign client to user-service
@FeignClient(name="user-service")
public interface UserClient {
@GetMapping("/users/{id}")
User getUser(@PathVariable("id") Long id);
}Controller
@RestController
@RequestMapping("/orders")
public class OrderController {
private final KafkaTemplate<String,String> kafka;
private final UserClient userClient;
public OrderController(KafkaTemplate<String,String> k, UserClient u){this.kafka=k;this.userClient=u;}
@PostMapping
public ResponseEntity<String> create(@RequestParam Long userId){
User user = userClient.getUser(userId);
// create order (omitted for brevity)
kafka.send("orders", "ORDER_CREATED:"+userId);
return ResponseEntity.ok("order created for " + user.getUsername());
}
}application.yml
server:
port: 8082
spring:
application:
name: order-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
kafka:
bootstrap-servers: localhost:90926) payment-service
Purpose: Consume ORDER_CREATED events and process payments.
pom.xml deps (key)
<dependency>spring-boot-starter-web</dependency>
<dependency>org.springframework.kafka:spring-kafka</dependency>
<dependency>spring-cloud-starter-netflix-eureka-client</dependency>Main class
@SpringBootApplication
@EnableEurekaClient
public class PaymentServiceApplication{ public static void main(String[] args){ SpringApplication.run(PaymentServiceApplication.class,args);} }Kafka listener
@Service
public class PaymentListener {
@KafkaListener(topics = "orders", groupId = "payment_group")
public void onMessage(String msg){
if(msg.startsWith("ORDER_CREATED:")){
String userId = msg.split(":")[1];
// process payment (omitted)
System.out.println("Processed payment for userId=" + userId);
}
}
}application.yml
server:
port: 8083
spring:
application:
name: payment-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
spring:
kafka:
bootstrap-servers: localhost:9092Docker & Docker Compose (local)
Dockerfiles: each service can use a minimal Dockerfile:
FROM eclipse-temurin:17-jdk-jammy
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]docker-compose.yml (essential services)