Build a Full Reactive Stack Backend with Spring Cloud, WebFlux, and Eureka

This guide walks through creating a fully reactive microservice architecture using Spring Cloud Finchley, WebFlux, and Spring Data Reactive, including setting up a Eureka service registry, building account and customer services with reactive MongoDB repositories, configuring load‑balanced WebClient calls, and demonstrating load‑balancing across multiple instances.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Build a Full Reactive Stack Backend with Spring Cloud, WebFlux, and Eureka

Preparation

To follow this example you need a service registry, two microservices, and a database. The registry will be a single‑node Eureka Server. The microservices are an Account service and a Customer service, each exposing simple reactive APIs and using their own databases. For the database we use MongoDB (run via Docker) because Spring Data Reactive currently supports MongoDB, Redis, and Cassandra.

docker run -d --name mongo -p 27017:27017 mongo

Service Registry

Create a basic Spring Boot project named eureka-server and add the Eureka Server starter dependency.

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

Configure application.yml:

spring:
  application:
    name: eureka-server
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://localhost:8000/eureka/
server:
  port: 8000

Add the annotations and main class:

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

Account Service

Create a Spring Boot project named cloud-account. Add the following dependencies:

<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>
<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-test</artifactId>
    <scope>test</scope>
</dependency>

Application configuration:

spring:
  application:
    name: cloud-account
server:
  port: 8100
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka/

Define the Account entity:

@AllArgsConstructor
@NoArgsConstructor
@Data
@Document(collection = "accounts")
public class Account {
    @Id
    private String id;
    private String customerId;
    private Double amount;
}

Create a reactive repository:

public interface AccountMongoReactiveRepository extends ReactiveCrudRepository<Account, String> {
    Flux<Account> findByCustomerId(String customerId);
}

Expose a simple controller:

@RequestMapping("/account")
@RestController
public class AccountController {
    @Autowired
    private AccountMongoReactiveRepository repository;

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

Customer Service

Create a Spring Boot project named cloud-customer with the same dependencies as the account service.

Configuration:

spring:
  application:
    name: cloud-customer
server:
  port: 8200
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka/

Customer entity:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "customers")
public class Customer {
    @Id
    private String id;
    private String name;
    private String mobile;
}

Reactive repository:

public interface CustomerMongoReactiveRepository extends ReactiveCrudRepository<Customer, String> {}

Configure a load‑balanced WebClient:

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

Customer controller (CRUD + call to account service):

@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);
    }
}

Testing

Start two instances of the cloud-account service (different ports) and invoke http://localhost:8200/customer/{id}/account. The timestamps in the logs show that WebClient distributes the calls between the two instances, confirming load balancing.

Conclusion

By using reactive programming for service registration, inter‑service calls, and data access, the example achieves a full reactive stack backend. This demonstrates how Spring Cloud Finchley, WebFlux, and Spring Data Reactive can be combined to build non‑blocking microservices, though adopting a reactive mindset may require additional learning.

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.

reactive-programmingeurekaWebFluxSpring CloudMongoDB
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

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.