Lettuce Client with Spring Boot

Integrating the Lettuce Client with Spring Boot for Non-Blocking Redis Operations

In today's world of microservices and distributed systems, performance and scalability are critical. One way to achieve high performance is through effective caching, and Redis is one of the most popular in-memory data stores available today. In this blog post, we'll explore how to integrate the Lettuce client with Spring Boot to perform non-blocking Redis operations.

What is Lettuce?

Lettuce is a scalable thread-safe Redis client for Java that utilizes asynchronous and reactive programming paradigms. Unlike traditional blocking clients, Lettuce allows for non-blocking communication with Redis, which can significantly improve the performance of applications that rely on Redis for caching or data storage.

Prerequisites

  • Java Development Kit (JDK) 11 or later
  • Spring Boot 2.5 or later
  • Redis server installed and running
  • Maven for dependency management

Setting Up Your Spring Boot Application

To get started, create a new Spring Boot project using Spring Initializr. Make sure to include the following dependencies:

  • Spring Web
  • Spring Data Redis
  • Lettuce (This is usually included as the default client for Spring Data Redis)

Once the project is generated, download and extract it into your workspace.

Configure Redis in application.properties

Open the src/main/resources/application.properties file and add your Redis server configuration:

    
spring.redis.host=localhost
spring.redis.port=6379
    

Creating the Model

Let's create a simple domain model representing a Customer. This model will be stored in Redis:

    
package com.example.demo.model;

import java.io.Serializable;

public class Customer implements Serializable {
    private String id;
    private String name;
    private String email;

    // Constructors, getters, and setters
    public Customer() {}

    public Customer(String id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }
}
    

Creating the Repository

Next, create a repository class that will use the Lettuce client to perform non-blocking operations:

    
package com.example.demo.repository;

import com.example.demo.model.Customer;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Repository
public class CustomerRepository {
    private final ReactiveRedisTemplate<String, Customer> reactiveRedisTemplate;

    public CustomerRepository(ReactiveRedisTemplate<String, Customer> reactiveRedisTemplate) {
        this.reactiveRedisTemplate = reactiveRedisTemplate;
    }

    public Mono<Customer> save(Customer customer) {
        return reactiveRedisTemplate.opsForValue().set(customer.getId(), customer)
                .then(Mono.just(customer));
    }

    public Mono<Customer> findById(String id) {
        return reactiveRedisTemplate.opsForValue().get(id);
    }

    public Mono<Void> deleteById(String id) {
        return reactiveRedisTemplate.opsForValue().delete(id);
    }

    public Flux<Customer> findAll() {
        return reactiveRedisTemplate.keys("*")
                .flatMap(reactiveRedisTemplate.opsForValue()::get);
    }
}
    

Creating the Controller

Now, we will create a REST controller to expose our repository methods:

    
package com.example.demo.controller;

import com.example.demo.model.Customer;
import com.example.demo.repository.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/api/customers")
public class CustomerController {
    
    private final CustomerRepository customerRepository;

    @Autowired
    public CustomerController(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }

    @PostMapping
    public Mono<ResponseEntity<Customer>> createCustomer(@RequestBody Customer customer) {
        return customerRepository.save(customer)
                .map(savedCustomer -> new ResponseEntity<>(savedCustomer, HttpStatus.CREATED));
    }

    @GetMapping("/{id}")
    public Mono<ResponseEntity<Customer>> getCustomer(@PathVariable String id) {
        return customerRepository.findById(id)
                .map(customer -> new ResponseEntity<>(customer, HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    @DeleteMapping("/{id}")
    public Mono<ResponseEntity<Void>> deleteCustomer(@PathVariable String id) {
        return customerRepository.deleteById(id)
                .then(Mono.just(new ResponseEntity<Void>(HttpStatus.NO_CONTENT)));
    }

    @GetMapping
    public Flux<Customer> getAllCustomers() {
        return customerRepository.findAll();
    }
}
    

Run the Application

Navigate to your project directory and run your Spring Boot application using:

    
mvn spring-boot:run
    

Ensure your Redis server is running. The application will be accessible at http://localhost:8080/api/customers.

Testing the API

You can use Postman or curl commands to test the CRUD operations.

Create a Customer

    
curl -X POST -H "Content-Type: application/json" -d '{"id": "1", "name": "Jane Doe", "email": "jane@example.com"}' http://localhost:8080/api/customers
    

Retrieve a Customer

    
curl -X GET http://localhost:8080/api/customers/1
    

Delete a Customer

    
curl -X DELETE http://localhost:8080/api/customers/1
    

Get All Customers

    
curl -X GET http://localhost:8080/api/customers
    

Conclusion

In this blog post, we have demonstrated how to integrate the Lettuce client with a Spring Boot application to perform non-blocking Redis operations. By leveraging the reactive programming capabilities of Spring WebFlux and Lettuce, we can build highly performant applications that can handle a large number of concurrent connections. This integration is particularly useful for modern applications that demand resilience and scalability. Happy coding!

Previous Post Next Post

Blog ads

ads