Overview
Microservices architecture breaks down an application into loosely coupled, independently deployable services. Spring Boot combined with Spring Cloud provides a powerful toolkit to build scalable, maintainable microservices. This article walks you through creating a complete microservices-based system using Spring Boot and Spring Cloud, including:
- Service Discovery with Eureka
- API Gateway with Spring Cloud Gateway
- Configuration with Spring Cloud Config
- RESTful microservices
- Inter-service communication with OpenFeign
- Circuit Breaker with Resilience4j
Project Architecture
We will build the following microservices:
- Config Server – Centralized configuration
- Eureka Server – Service discovery
- API Gateway – Gateway to route requests
- User Service – Example microservice
- Order Service – Another example microservice
+-----------------+
| Config Server |
+--------+--------+
|
+-------------------+-------------------+
| |
+-------v--------+ +--------v--------+
| Eureka | <-----------------> | API Gateway |
+----------------+ +---------+--------+
|
+-------------------------+-------------------------+
| | |
+---------v--------+ +--------v--------+ +--------v--------+
| User Service | | Order Service | | Other Services |
+------------------+ +------------------+ +------------------+
1. Config Server
Dependencies
In pom.xml
:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Main Application
@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:
git:
uri: https://github.com/your-org/your-config-repo
2. Eureka Server
Dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Main Application
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
application.yml
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
3. API Gateway
Dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-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
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/users/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/orders/**
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
4. User Service
Dependencies
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
application.yml
server:
port: 8081
spring:
application:
name: user-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
Main Application
@SpringBootApplication
@EnableFeignClients
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
UserController
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping
public List<String> getAllUsers() {
return List.of("Alice", "Bob", "Charlie");
}
}
5. Order Service
application.yml
server:
port: 8082
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
Main Application
@SpringBootApplication
@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")
List<String> getUsers();
}
OrderController
@RestController
@RequestMapping("/orders")
public class OrderController {
private final UserClient userClient;
public OrderController(UserClient userClient) {
this.userClient = userClient;
}
@GetMapping
public Map<String, Object> getOrders() {
return Map.of(
"orderId", UUID.randomUUID(),
"users", userClient.getUsers()
);
}
}
6. Circuit Breaker with Resilience4j
Dependencies
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
</dependency>
Wrap Feign Client Method
@CircuitBreaker(name = "userService", fallbackMethod = "fallbackUsers")
public List<String> getUsers() {
return userClient.getUsers();
}
public List<String> fallbackUsers(Throwable t) {
return List.of("Default User");
}
7. Central Configuration Repository (Optional)
In your Git repo (used by Config Server), create user-service.yml
, order-service.yml
, etc.
Example: user-service.yml
spring:
application:
name: user-service
some:
external:
value: "User config from Git"
Running the System
- Start Config Server
- Start Eureka Server
- Start User Service and Order Service
- Start API Gateway
Testing the System
- Service Discovery: Visit http://localhost:8761 to see all registered services.
- User Service:
http://localhost:8080/users
- Order Service:
http://localhost:8080/orders
Conclusion
Using Spring Boot and Spring Cloud, we can build robust and scalable microservice architectures with minimal configuration. The ecosystem provides everything from discovery, routing, configuration, communication, to fault tolerance — making it easier to focus on business logic.