Spring Boot Integration

Introduction

Running Redis from redis-cli teaches you the commands, but production applications need a client library. In the Java ecosystem, two drivers dominate—Jedis and Lettuce—while Spring Data Redis provides a convenient abstraction layer on top of either one. This chapter compares the drivers, shows how Spring Data Redis simplifies daily operations, and walks through a complete Spring Boot project that connects to Redis, caches method results, and implements a practical distributed lock.

Prerequisites

  • Java 17 or newer
  • Maven or Gradle installed
  • Familiarity with Spring Boot basics
  • A running Redis server (local or Docker) on port 6379

Jedis vs Lettuce

Both libraries are mature and well-supported. The choice usually comes down to threading model and API preference.

FeatureJedisLettuce
ThreadingBlocking I/O; use connection poolsAsync non-blocking I/O on Netty; share one connection
Reactive APINo native supportFull support for Mono and Flux
Sentinel / ClusterSupportedSupported with better topology refresh
Spring Boot defaultOptionalDefault since Spring Boot 2.0
MaintenanceActiveActive (preferred by Spring team)

Tip

Start with Lettuce

If you are building a new Spring Boot application, use Lettuce. It is the default driver, supports reactive stacks, and eliminates connection-pool tuning headaches.

A Minimal Jedis Example

xml
<!-- pom.xml -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>5.1.0</version>
</dependency>

A Minimal Lettuce Example

xml
<!-- pom.xml -->
<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>6.3.0.RELEASE</version>
</dependency>

Spring Data Redis

Spring Data Redis abstracts driver details behind familiar RedisTemplate and StringRedisTemplate APIs. It also provides annotation-driven caching that can replace manual Redis calls entirely.

Adding Dependencies

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

No version is needed because Spring Boot manages it.

Connection Settings

Spring Boot auto-configures a StringRedisTemplate and a RedisConnectionFactory from these properties.

Using StringRedisTemplate

StringRedisTemplate uses StringRedisSerializer for both keys and values, which is what you want for most text-based caching.

Working with Hashes

Serialization: The JSON Problem

By default, RedisTemplate uses Java serialization, which produces unreadable binary data. For JSON storage, configure a custom RedisTemplate:

Warning

JSON Type Information

GenericJackson2JsonRedisSerializer embeds a @class field so Jackson can deserialize polymorphic types. If you refactor package names, old cache entries may fail to deserialize. Plan cache versioning or TTLs around major refactors.

Annotation-Driven Caching

Spring Cache abstracts the cache provider entirely. Switching from an in-memory ConcurrentHashMap to Redis is a one-line configuration change.

Enable Caching

java
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@EnableCaching
public class CacheConfig {
}

Cache Annotations

Custom TTL per Cache

Spring Cache does not expose TTL directly in annotations. Define it in configuration:

Implementing a Distributed Lock

Distributed locks prevent multiple instances of your application from performing the same critical operation simultaneously. Redis makes this possible with SETNX (Set if Not eXists) and expiration.

Basic Lock with StringRedisTemplate

Warning

This Is a Simplified Lock

The example above omits token verification and lock extension. For production systems, use Redisson or implement the full Redlock algorithm with token-matching Lua scripts to avoid accidentally releasing another client's lock.

Connecting to Sentinel and Cluster

Spring Boot connects to Sentinel or Cluster with purely configuration changes—no code modifications required.

Sentinel

yaml
spring:
  data:
    redis:
      sentinel:
        master: mymaster
        nodes:
          - sentinel1.example.com:26379
          - sentinel2.example.com:26379
          - sentinel3.example.com:26379
      password: your-master-password

Cluster

yaml
spring:
  data:
    redis:
      cluster:
        nodes:
          - redis1.example.com:6379
          - redis2.example.com:6379
          - redis3.example.com:6379
        max-redirects: 3

The StringRedisTemplate and cache annotations work identically regardless of topology.

FAQ

Should I use Jedis or Lettuce with Spring Boot?

Use Lettuce unless you have a specific reason not to. It is the Spring Boot default, handles high concurrency without connection pools, and supports reactive programming.

Why does my cached object fail to deserialize?

Common causes: the class was moved or renamed, Jackson does not have a no-arg constructor, or the serializer was changed without clearing old cache entries. Set a TTL or manually flush the cache after deploys that change serialized classes.

Can I use Spring Cache with Redis Cluster?

Yes. The cache abstraction is agnostic to the underlying topology. Configure spring.data.redis.cluster.nodes and Spring Data Redis handles routing.

How do I monitor cache hit rates in Spring?

Enable Micrometer metrics:

yaml
management:
  metrics:
    enable:
      cache: true

Then observe cache.gets, cache.hits, and cache.misses in your metrics dashboard.

Is RedisTemplate thread-safe?

Yes. Once configured, RedisTemplate (and StringRedisTemplate) can be shared across multiple threads. Under Lettuce, the connection itself is multiplexed across threads safely.