ReviseAlgo Logo

Caching with Redis

Redis as a Cache Backend — Setup and Configuration

Configuring RedisConnectionFactory, RedisTemplate, and serializer configurations.

Last Updated: June 15, 2026 15 min read

Introduction

By default, Spring Boot uses in-memory cache implementations like ConcurrentHashMap. However, local in-memory caches are confined to a single JVM instance, which creates consistency gaps in distributed, multi-replica cloud environments. **Redis** serves as a centralized, high-performance in-memory key-value database that synchronizes cache states globally.

Integrating Redis requires overriding Spring's cache config and implementing specialized client connections, serializer strategies, and cache managers.

Why It Matters

Using local caching in a clustered environment causes consistency bugs: Node A updates a database value, but Node B continues serving outdated values from its local memory. Centralizing caching with Redis solves this problem. It also allows cached items to survive application restarts, reducing cold-start database overload.

Real-World Analogy

In a small coffee shop, each barista keeps their own cup inventory shelf (local cache). If one barista receives a new cup type, others don't know (inconsistency). In a large franchise, the baristas share a centralized, central cupboard (Redis). When a cup is added, replaced, or removed, everyone has immediate access to the updated inventory.

How It Works

To connect Spring Boot to Redis:

  • Connection Library: Spring Boot uses a driver library, primarily **Lettuce** (non-blocking, reactive, sharing a single physical connection) or **Jedis** (blocking, requiring thread pools).
  • Connection Factory: RedisConnectionFactory configures the host IP, port, TLS security, and pooling details.
  • RedisTemplate: A utility class that handles data interactions with Redis (e.g. hash, list, string operations) using specific serializers.
  • RedisCacheManager: Overrides Spring's default local CacheManager, translating @Cacheable annotations into Redis GET and SET commands.

Internal Architecture

Because Redis stores data as binary payloads, Java objects must be serialized to bytes when saving and deserialized when reading.

The default Java Serialization (JDK) generates unreadable binary structures, requires class definitions to be identical on all nodes, and introduces security vulnerabilities. Modern production architectures use **JSON serialization** (e.g. GenericJackson2JsonRedisSerializer), which stores clean, cross-compatible JSON strings.

Visual Explanation

Loading diagram…

Practical Example

Here is a configuration class setting up connection factories and dynamic RedisCacheManager with Jackson JSON serializer:

Common Mistakes

  • JDK Serialization Usage: Storing binary blobs in Redis. This makes it impossible to query or update keys directly via the Redis CLI, and causes serialization crashes if class fields change.
  • No TCP Connection Timeouts: Omitting client connection timeouts. If Redis goes offline, the application will block threads indefinitely trying to connect, causing server pool exhaustion.
  • Class Type Deserialization Failures: Caching polymorphic types using Jackson without registering target class metadata, leading to ClassCastExceptions upon reading.

Quick Quiz

Q1: Which client driver is modern Spring Boot configured to use by default to interact with Redis clusters?

A) Jedis

B) Lettuce

C) Redisson

D) JDBC-Redis

Answer: B — Lettuce is Spring Boot's default client. It is built on Netty and is non-blocking, allowing multiple threads to share a single connection safely.

Q2: What is the primary benefit of configuring Jackson serialization over default Java serialization in RedisCacheManager?

A) Jackson increases raw payload transmission speed by 200%.

B) It stores data as human-readable JSON, enabling multi-language compatibility and direct Redis CLI inspection.

C) It bypasses the need for registering cache names.

D) It encrypts cache values automatically.

Answer: B — Jackson converts Java objects into JSON strings. This keeps data readable in the Redis CLI and makes it compatible with non-Java services.

Scenario-Based Challenge

Production Scenario:

You configure your application to use Redis. When Redis experiences a network partitioning event, your Spring Boot API endpoints freeze, and users see HTTP 504 Gateway Timeouts. How do you rewrite your configuration so that caching fails gracefully (fallback to database querying) instead of blocking requests when Redis is unreachable?

View Solution

By default, Spring Boot caching exceptions bubble up and block execution. To implement a fallback mechanism:

1. Implement the CachingConfigurer interface in your config class.
2. Override the errorHandler() method to return a custom CacheErrorHandler that logs connection errors but allows the call flow to proceed to the database:


Return this handler in your config class:

Debugging Exercise

Broken Configuration:

Your application throws a SerializationException at runtime: Could not write JSON: Document contains a self-referencing loop. The class being cached is:

View Debugging Steps & Fix

Reason: Bidirectional relationships in JPA (Order -> OrderItem -> Order) create infinite loops during JSON serialization. When the Jackson serializer attempts to serialize the Order, it hits OrderItem, which references Order back, causing stack overflow.

The Fix: Add @JsonIgnore or @JsonManagedReference / @JsonBackReference annotations to resolve cycle loops:

Interview Questions

1. Conceptual: Why is Lettuce preferred over Jedis as the default Redis client in modern Spring Boot applications?

Jedis uses a blocking IO approach where each thread gets its own dedicated connection from a pool. Under heavy concurrency, thread context switching and connection exhaustion degrade performance. Lettuce is built on Netty and utilizes non-blocking, asynchronous event loops. It allows multiple concurrent threads to share a single TCP connection safely, reducing connection pooling overhead and supporting reactive programming patterns natively.

2. Technical: How do you configure custom JSON serialization for Redis keys and values in a Spring Boot configuration class?

Configure keys and values serializers using RedisCacheConfiguration. Set keys to use StringRedisSerializer and values to use GenericJackson2JsonRedisSerializer inside the cacheDefaults definition:
RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()) This ensures that object type information is embedded in the JSON structure, allowing Jackson to deserialize it back to the concrete class type automatically upon retrieval.

Production Considerations

In production environments, ensure you configure Lettuce with a commandTimeout and keepAlive configurations. Configure Redis Sentinel or Cluster to support high availability (HA). Monitor active connection metrics via JMX.