Building a Reactive Microservice Architecture with Spring Cloud, WebFlux, and MongoDB

This tutorial demonstrates how to create a full‑reactive microservice system using Spring Cloud Finchley, WebFlux, Spring Data Reactive MongoDB, and Eureka for service discovery, covering project setup, service registration, reactive repositories, controllers, inter‑service calls with WebClient, and load‑balanced testing.

Top Architect
Top Architect
Top Architect
Building a Reactive Microservice Architecture with Spring Cloud, WebFlux, and MongoDB

Spring Cloud traditionally uses synchronous REST calls via RestTemplate or Feign, but with Spring Cloud Finchley we can build a completely reactive stack using WebFlux and Spring Data Reactive.

Prerequisites : a single‑node Eureka server, two microservices (account and customer), and a MongoDB instance (run via Docker).

Start Eureka Server :

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
spring:
  application:
    name: eureka-server
  eureka:
    client:
      register-with-eureka: false
      fetch-registry: false
      service-url:
        defaultZone: http://localhost:8000/eureka/
server:
  port: 8000
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

Account Service (cloud‑account) :

docker run -d --name mongo -p 27017:27017 mongo
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
spring:
  application:
    name: cloud-account
server:
  port: 8100
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka/
@AllArgsConstructor
@NoArgsConstructor
@Data
@Document(collection = "accounts")
public class Account {
    @Id
    private String id;
    private String customerId;
    private Double amount;
}
public interface AccountMongoReactiveRepository extends ReactiveCrudRepository<Account, String> {
    Flux<Account> findByCustomerId(String customerId);
}
@RequestMapping("/account")
@RestController
public class AccountController {
    @Autowired
    private AccountMongoReactiveRepository repository;

    @GetMapping("/customer/{customer}")
    public Flux<Account> findByCustomer(@PathVariable("customer") String customer) {
        System.out.println("Customer => " + customer + " [ " +
            LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss.SSS")) + " ]");
        return repository.findByCustomerId(customer);
    }
}

Customer Service (cloud‑customer) uses the same dependencies and a similar configuration, only changing the application name and port (8200).

spring:
  application:
    name: cloud-customer
server:
  port: 8200
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "customers")
public class Customer {
    @Id
    private String id;
    private String name;
    private String mobile;
}
public interface CustomerMongoReactiveRepository extends ReactiveCrudRepository<Customer, String> {}
@RestController
@RequestMapping("/customer")
public class CustomerController {
    @Autowired
    private CustomerMongoReactiveRepository repository;
    @Autowired
    private WebClient.Builder webClientBuilder;

    @GetMapping("")
    public Flux<Customer> list() {
        return repository.findAll();
    }

    @GetMapping("/{id}")
    public Mono<Customer> get(@PathVariable String id) {
        return repository.findById(id);
    }

    @PostMapping("")
    public Mono<Customer> create(@RequestBody Customer customer) {
        return repository.save(customer);
    }

    @PutMapping("/{id}")
    public Mono<Customer> update(@PathVariable("id") String id, @RequestBody Customer customer) {
        customer.setId(id);
        return repository.save(customer);
    }

    @DeleteMapping("/{id}")
    public Mono<Void> delete(@PathVariable String id) {
        return repository.deleteById(id);
    }

    @GetMapping("/{id}/account")
    public Flux<Account> getAllAccounts(@PathVariable String id) {
        return webClientBuilder.baseUrl("http://cloud-account/account/")
                .build()
                .get()
                .uri("/customer/" + id)
                .retrieve()
                .bodyToFlux(Account.class);
    }
}

WebClient Configuration (load‑balanced):

@Configuration
public class WebClientConfig {
    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
}

Running two instances of cloud‑account (ports 8100 and 8101) and invoking http://localhost:8200/customer/{id}/account shows alternating timestamps, confirming that WebClient together with Ribbon provides client‑side load balancing.

Conclusion : The example covers service registration, reactive data access, and non‑blocking inter‑service calls, achieving a full reactive stack backend. It illustrates the practical steps needed to move from traditional synchronous Spring Cloud services to a fully reactive, cloud‑native architecture.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Microservicesreactive-programmingeurekaWebFluxSpring CloudMongoDB
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.