How to Build Reactive Microservices with Spring WebFlux, Spring Cloud, and MongoDB
This tutorial walks you through creating a reactive microservice architecture using Spring WebFlux, Spring Cloud components such as Eureka and Gateway, and Spring Data Reactive MongoDB, covering dependency setup, controller and repository code, service discovery, load‑balanced inter‑service calls, gateway routing, Docker deployment, and testing with curl.
This guide shows how to build a fully reactive microservice system with Spring 5 and Spring Boot 2, using Spring WebFlux, Spring Cloud (Eureka, Gateway, load‑balanced WebClient) and Spring Data Reactive MongoDB.
Step 1 – Add Spring WebFlux
Add the WebFlux starter dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>Define a reactive REST controller. Methods that return a single value use Mono, while methods that return a collection use Flux:
@RestController
public class AccountController {
private static final Logger LOGGER = LoggerFactory.getLogger(AccountController.class);
@Autowired
private AccountRepository repository;
@GetMapping("/customer/{customerId}")
public Flux<Account> findByCustomer(@PathVariable String customerId) {
LOGGER.info("findByCustomer: {}", customerId);
return repository.findByCustomerId(customerId);
}
@GetMapping("/{id}")
public Mono<Account> findById(@PathVariable String id) {
LOGGER.info("findById: {}", id);
return repository.findById(id);
}
@PostMapping
public Mono<Account> create(@RequestBody Account account) {
LOGGER.info("create: {}", account);
return repository.save(account);
}
}Step 2 – Add Reactive MongoDB Support
Add the reactive MongoDB starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>Define the domain entity:
@Document
public class Account {
@Id
private String id;
private String number;
private String customerId;
private int amount;
// getters and setters omitted
}Create a repository that extends ReactiveCrudRepository and adds a custom query method:
public interface AccountRepository extends ReactiveCrudRepository<Account, String> {
Flux<Account> findByCustomerId(String customerId);
}Step 3 – Enable Service Discovery with Eureka
Add the Eureka client starter:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>Annotate the main class with @EnableDiscoveryClient and @SpringBootApplication so that the service registers itself with the Eureka server (default UI at http://localhost:8761):
@SpringBootApplication
@EnableDiscoveryClient
public class AccountApplication {
public static void main(String[] args) {
SpringApplication.run(AccountApplication.class, args);
}
}Step 4 – Inter‑service Calls with Load‑Balanced WebClient
Declare a load‑balanced WebClient.Builder bean:
@Bean
@LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}Inject the builder into a controller and combine data from the local repository (a Mono) with remote accounts (a Flux) to produce a merged result:
@Autowired
private WebClient.Builder webClientBuilder;
@GetMapping("/{id}/with-accounts")
public Mono<CustomerDto> findByIdWithAccounts(@PathVariable String id) {
LOGGER.info("findByIdWithAccounts: {}", id);
Flux<Account> accounts = webClientBuilder.build()
.get()
.uri("http://account-service/customer/{customerId}", id)
.retrieve()
.bodyToFlux(Account.class);
return accounts.collectList()
.map(list -> new CustomerDto(id, list))
.mergeWith(repository.findById(id))
.collectList()
.map(CustomerMapper::map);
}Step 5 – API Gateway with Spring Cloud Gateway
Add the gateway starter:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>Enable discovery client and disable gateway registration in Eureka (set eureka.client.registerWithEureka=false in application.yml if desired). The main class is similar to the one used for Eureka:
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}Configure routes in application.yml so that /account/** and /customer/** are forwarded to the corresponding services and the path is rewritten to match the service’s own endpoint:
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: account-service
uri: lb://account-service
predicates:
- Path=/account/**
filters:
- RewritePath=/account/(?<segment>.*), /${segment}
- id: customer-service
uri: lb://customer-service
predicates:
- Path=/customer/**
filters:
- RewritePath=/customer/(?<segment>.*), /${segment}Step 6 – Run and Test the Sample System
Start a MongoDB container (Docker):
docker run -d --name mongo -p 27017:27017 mongoStart the Eureka server (default localhost:8761) and then launch the microservices. To run a second instance of account-service on a different port, use the JVM argument -Dserver.port=2223:
java -jar discovery-service-1.0-SNAPSHOT.jar
java -jar account-service-1.0-SNAPSHOT.jar
java -Dserver.port=2223 -jar account-service-1.0-SNAPSHOT.jar
java -jar customer-service-1.0-SNAPSHOT.jar
java -jar gateway-service-1.0-SNAPSHOT.jarInsert test data through the gateway (exposed at localhost:8090):
# Create a customer
curl -H "Content-Type: application/json" -X POST \
-d '{"firstName":"John","lastName":"Scott","age":30}' \
http://localhost:8090/customer
# Create accounts for that customer (replace {customerId} with the id returned above)
curl -H "Content-Type: application/json" -X POST \
-d '{"number":"1234567890","amount":5000,"customerId":"{customerId}"}' \
http://localhost:8090/accountRetrieve the customer together with its accounts:
curl http://localhost:8090/customer/{customerId}/with-accountsThe gateway forwards the request to customer-service, which uses the load‑balanced WebClient to call account-service, merges the data, and returns a combined JSON payload.
Conclusion
Spring 5 and Spring Boot 2 provide a complete stack for building reactive microservices. By combining Spring WebFlux with Spring Cloud components (Eureka, Gateway, load‑balanced WebClient) and reactive NoSQL support (MongoDB), developers can create scalable, non‑blocking services that coexist with traditional synchronous REST services.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
