Home/Learn/Spring Boot/Spring Boot with Redis

Spring Boot with Redis

Intermediate
Advanced

Spring Data Redis provides RedisTemplate and the @Cacheable abstraction over Redis; cache-aside, write-through, and pub/sub patterns are all supported out of the box.

Overview

Spring Boot's `spring-boot-starter-data-redis` auto-configures a `RedisTemplate` (low-level key-value operations) and a `StringRedisTemplate` using Lettuce as the default async client. The most common use cases are: **caching** (`@Cacheable` with `RedisCacheManager`), **session storage** (`spring-session-data-redis` for distributed sessions), **rate limiting** (atomic counters with TTL), **pub/sub** (`RedisMessageListenerContainer`), and **distributed locks** (Redisson or `SET NX PX` pattern). Redis's single-threaded execution and atomic operations make it ideal for distributed coordination without transaction overhead.

@Cacheable with RedisCacheManager

Replace an in-process Caffeine/Ehcache with Redis by configuring `RedisCacheManager` as the `CacheManager` bean. `@Cacheable` checks the Redis cache before executing the method; `@CacheEvict` removes an entry; `@CachePut` always writes. Use a `RedisCacheConfiguration` to set TTL, key prefix, and JSON serialisation.

Spring Boot — @Cacheable with RedisCacheManager
@Configuration
class RedisCacheConfig {
    @Bean
    CacheManager cacheManager(RedisConnectionFactory cf) {
        RedisCacheConfiguration cfg = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofMinutes(30))
            .prefixCacheNameWith("myapp::")
            .serializeValuesWith(                           // JSON instead of Java serialisation
                RedisSerializationContext.SerializationPair
                    .fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return RedisCacheManager.builder(cf)
            .cacheDefaults(cfg)
            .withCacheConfiguration("products", cfg.entryTtl(Duration.ofHours(1)))
            .build();
    }
}

@Service
class ProductService {
    @Cacheable(value = "products", key = "#id")
    public Product findById(Long id) { return productRepo.findById(id).orElseThrow(); }

    @CacheEvict(value = "products", key = "#product.id")
    public Product update(Product product) { return productRepo.save(product); }

    @CacheEvict(value = "products", allEntries = true)
    public void refreshAll() { /* clear all cache entries */ }
}

RedisTemplate for Low-Level Operations

`RedisTemplate` gives direct access to Redis data structures: strings, hashes, lists, sets, sorted sets. Use `opsForValue()` for simple string key-value, `opsForHash()` for field maps, `opsForZSet()` for leaderboards. Configure with `StringRedisSerializer` for keys and `GenericJackson2JsonRedisSerializer` for values to keep Redis keys readable.

Spring Boot — RedisTemplate rate limiter and hash operations
@Service
@RequiredArgsConstructor
class RateLimiter {
    private final RedisTemplate<String, String> redis;

    public boolean isAllowed(String userId, int maxPerMinute) {
        String key = "rate:" + userId + ":" + Instant.now().truncatedTo(ChronoUnit.MINUTES);
        Long count = redis.opsForValue().increment(key);
        if (count == 1) redis.expire(key, Duration.ofMinutes(2));  // set TTL on first increment
        return count <= maxPerMinute;
    }
}

@Service
@RequiredArgsConstructor
class SessionCache {
    private final RedisTemplate<String, Object> redis;

    public void save(String sessionId, Map<String, Object> data) {
        redis.opsForHash().putAll("session:" + sessionId, data);
        redis.expire("session:" + sessionId, Duration.ofHours(1));
    }

    public Object get(String sessionId, String field) {
        return redis.opsForHash().get("session:" + sessionId, field);
    }
}

Pub/Sub and Distributed Lock Pattern

Redis pub/sub broadcasts messages to all subscribers on a channel — useful for cache invalidation across pods. For distributed locks, use the `SET key value NX PX ttl` pattern (set if not exists, with TTL to prevent deadlocks). Redisson's `RLock` implements the full Redlock algorithm for multi-node safety.

Spring Boot — Redis pub/sub and distributed lock
// Pub/Sub — cache invalidation broadcast
@Configuration
class RedisPubSubConfig {
    @Bean
    RedisMessageListenerContainer listenerContainer(
            RedisConnectionFactory cf, MessageListener invalidationListener) {
        var container = new RedisMessageListenerContainer();
        container.setConnectionFactory(cf);
        container.addMessageListener(invalidationListener,
            new PatternTopic("cache-invalidation:*"));
        return container;
    }
}

@Component
class CacheInvalidationListener implements MessageListener {
    @Override
    public void onMessage(Message msg, byte[] pattern) {
        String key = new String(msg.getBody());
        cacheManager.getCache("products").evict(key);
    }
}

// Simple distributed lock (SET NX PX)
public boolean tryLock(String lockKey, String owner, Duration ttl) {
    Boolean acquired = redis.opsForValue()
        .setIfAbsent(lockKey, owner, ttl);   // SET lockKey owner NX PX ttl
    return Boolean.TRUE.equals(acquired);
}

public void unlock(String lockKey, String owner) {
    // Lua script: atomic check-and-delete
    String script = "if redis.call('get',KEYS[1]) == ARGV[1] then " +
                    "return redis.call('del',KEYS[1]) else return 0 end";
    redis.execute(new DefaultRedisScript<>(script, Long.class),
                  List.of(lockKey), owner);
}

Key Points to Remember

  • 1@Cacheable with RedisCacheManager makes method results Redis-backed with per-cache TTL
  • 2Use GenericJackson2JsonRedisSerializer for human-readable JSON values in Redis
  • 3RedisTemplate.opsForValue().increment() + expire() implements atomic rate limiting
  • 4SET key value NX PX ttl is the foundation of a Redis distributed lock
  • 5Redis pub/sub broadcasts to all subscribers — useful for cache invalidation across pods
  • 6spring-session-data-redis stores HTTP session in Redis — enables stateless horizontally-scaled apps

Interview Questions

Sign in to ask Aria
1

How does @Cacheable with RedisCacheManager differ from an in-process cache?

EasyAmazon
2

How would you implement a rate limiter using Redis in Spring Boot?

MediumThoughtWorks
3

Why do you need a Lua script for the distributed lock unlock operation?

HardNetflix
4

What is the risk of not setting a TTL on a Redis lock key?

EasyBooking.com
5

How would you use Redis pub/sub to invalidate a local cache across multiple pods?

MediumZalando

Ask Aria about Spring Boot with Redis

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…