DEV Community

Dev Cookies
Dev Cookies

Posted on

๐Ÿš€ Redis as a Cache in Spring Boot โ€” Full Code & Tutorial

๐Ÿง  Introduction

Caching is one of the most effective ways to improve performance in microservices and monolithic applications. Redis is an ultra-fast, in-memory key-value store that integrates beautifully with Spring Boot via Spring Cache Abstraction.

This tutorial walks you through setting up Redis as a cache in a Spring Boot application with detailed code, configuration, and explanations.


โš™๏ธ Technologies Used

  • Spring Boot 3.x
  • Spring Web
  • Spring Cache
  • Spring Data Redis
  • Redis Server (locally or Docker)
  • Java 17+
  • Maven

๐Ÿ“ Project Structure

redis-cache-demo/
โ”œโ”€โ”€ controller/
โ”‚   โ””โ”€โ”€ ProductController.java
โ”œโ”€โ”€ config/
โ”‚   โ””โ”€โ”€ RedisConfig.java
โ”œโ”€โ”€ service/
โ”‚   โ””โ”€โ”€ ProductService.java
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ Product.java
โ”œโ”€โ”€ RedisCacheDemoApplication.java
โ””โ”€โ”€ resources/
    โ””โ”€โ”€ application.properties
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”ง 1. Add Dependencies (pom.xml)

<dependencies>
    <!-- Spring Boot Web Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Boot Cache -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    <!-- Redis Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- For JSON Serialization in Redis -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>

    <!-- Lombok (Optional) -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>
Enter fullscreen mode Exit fullscreen mode

๐ŸŒ 2. application.properties

# Redis config
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.timeout=60000

# Logging for visibility
logging.level.org.springframework.cache=DEBUG
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“ Tip: You can run Redis locally with Docker:

docker run --name redis -p 6379:6379 redis

๐Ÿ’ป 3. Main Class with Caching Enabled

@SpringBootApplication
@EnableCaching // ๐Ÿ”ฅ Enables Spring's cache abstraction
public class RedisCacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisCacheDemoApplication.class, args);
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฉ 4. Model Class: Product.java

package com.example.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product implements Serializable {
    private Long id;
    private String name;
    private Double price;
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Serializable is required because Redis stores data as binary by default.


๐Ÿ› ๏ธ 5. Redis Configuration

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.*;

import java.time.Duration;

@Configuration
public class RedisConfig {

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
        return RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(5)) // Set TTL for cache
            .disableCachingNullValues()
            .serializeValuesWith(RedisSerializationContext
                .SerializationPair
                .fromSerializer(new GenericJackson2JsonRedisSerializer()));
    }
}
Enter fullscreen mode Exit fullscreen mode

โš™๏ธ 6. Service Layer with Caching

package com.example.service;

import com.example.model.Product;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class ProductService {

    private final Map<Long, Product> productDb = new HashMap<>();

    public ProductService() {
        // Simulated database
        productDb.put(1L, new Product(1L, "iPhone 14", 89999.0));
        productDb.put(2L, new Product(2L, "MacBook Pro", 229999.0));
    }

    // CACHE READ
    @Cacheable(value = "productCache", key = "#id")
    public Product getProductById(Long id) {
        simulateSlowService(); // Simulate latency
        return productDb.get(id);
    }

    // CACHE WRITE / UPDATE
    @CachePut(value = "productCache", key = "#product.id")
    public Product updateProduct(Product product) {
        productDb.put(product.getId(), product);
        return product;
    }

    // CACHE DELETE
    @CacheEvict(value = "productCache", key = "#id")
    public void deleteProduct(Long id) {
        productDb.remove(id);
    }

    private void simulateSlowService() {
        try {
            Thread.sleep(3000); // Simulates DB latency
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“ก 7. REST Controller

package com.example.controller;

import com.example.model.Product;
import com.example.service.ProductService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/products")
@RequiredArgsConstructor
public class ProductController {

    private final ProductService productService;

    // GET (with cache)
    @GetMapping("/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable Long id) {
        return ResponseEntity.ok(productService.getProductById(id));
    }

    // PUT (update + refresh cache)
    @PutMapping
    public ResponseEntity<Product> updateProduct(@RequestBody Product product) {
        return ResponseEntity.ok(productService.updateProduct(product));
    }

    // DELETE (evict cache)
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteProduct(@PathVariable Long id) {
        productService.deleteProduct(id);
        return ResponseEntity.noContent().build();
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงช Example Request Flow

1. First Request (Cache Miss)

curl http://localhost:8080/products/1
Enter fullscreen mode Exit fullscreen mode

โœ… Output (slow): 3s response time
โณ DB hit, then cached


2. Second Request (Cache Hit)

curl http://localhost:8080/products/1
Enter fullscreen mode Exit fullscreen mode

โšก Output (fast): <1s
โœ… From Redis cache


3. Update Request (Cache Refresh)

curl -X PUT http://localhost:8080/products \
     -H "Content-Type: application/json" \
     -d '{"id":1,"name":"iPhone 15","price":95000}'
Enter fullscreen mode Exit fullscreen mode

โœ… Redis cache is updated


4. Delete Request (Evict Cache)

curl -X DELETE http://localhost:8080/products/1
Enter fullscreen mode Exit fullscreen mode

โœ… Cache for id=1 is evicted


๐Ÿ“Œ Redis Insight View (Optional GUI)

  • Install RedisInsight
  • Connect to Redis
  • View keys under productCache::1, etc.

๐Ÿง  Best Practices

  • Use meaningful cache names and keys
  • Apply TTL (Time-to-live) to avoid stale data
  • Avoid caching nulls or sensitive data
  • Use cache eviction/update smartly with business logic
  • Monitor with tools like RedisInsight or Spring Boot Actuator

๐Ÿ Conclusion

Using Redis as a cache in Spring Boot is a must-have performance booster for modern apps. With Spring's @Cacheable abstraction, it's easier than ever to implement caching with minimal effort.

By understanding how to configure TTL, handle serialization, and update cache entries, you can build robust and performant backend services.

Top comments (0)