Spring Boot and Redis

Spring Boot and Redis together form a powerful duo for building high‑performance, scalable applications.
Redis, as an in‑memory key‑value store, excels at caching, session handling, counters, and more.
Spring Boot’s auto‑configuration and the Spring Data Redis module make it effortless to tap into Redis’s capabilities from a Spring application.
Below is a practical guide that walks through the entire process—from setting up the environment to deploying a production‑ready configuration—while showcasing real‑world examples.

Component Minimum Version Notes
JDK 1.8+ Java 17 or newer is also fine.
Spring Boot 2.5.x or later The examples below use 2.7.x.
Redis Server 5.x, 6.x, or 7.x Any recent release works; just ensure it’s reachable.
IDE IntelliJ IDEA, VS Code, or similar Pick what you’re comfortable with.

If you don’t have Redis installed locally, a quick Docker run will give you a ready‑to‑use instance:

docker run -d --name redis-demo -p 6379:6379 redis:7-alpine

2. Adding Dependencies

Spring Boot’s starter for data‑access with Redis pulls in the core client library.
Lettuce is the default client; it’s non‑blocking and thread‑safe, making it a solid choice for most workloads.

Maven

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

Gradle

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

Tip: If you prefer the older Jedis client, add its dependency explicitly, but Lettuce is recommended for new projects.

3. Configuring the Connection

Spring Boot can auto‑configure a RedisConnectionFactory from properties in application.yml or application.properties.
Below is a YAML snippet that demonstrates a typical setup, including a connection pool.

spring:
  redis:
    host: localhost
    port: 6379
    password: ""          # leave empty if no password
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 1000ms
    timeout: 2000ms

Security note: In production, avoid hard‑coding passwords. Use environment variables or a secrets manager, and consider encrypting the value with spring.redis.password.

4. Using StringRedisTemplate

StringRedisTemplate is a convenience wrapper that handles string keys and values.
It’s ideal for simple caching, counters, or any scenario where the data is naturally textual.

@Service
public class CacheService {

    private final StringRedisTemplate template;

    public CacheService(StringRedisTemplate template) {
        this.template = template;
    }

    public void put(String key, String value, long timeout, TimeUnit unit) {
        template.opsForValue().set(key, value, timeout, unit);
    }

    public String get(String key) {
        return template.opsForValue().get(key);
    }

    public Long increment(String key) {
        return template.opsForValue().increment(key);
    }

    public Boolean delete(String key) {
        return template.delete(key);
    }
}

Example: Visit Counter

@RestController
@RequestMapping("/api")
public class VisitController {

    private final CacheService cache;
    private static final String VISIT_KEY = "site:visit:count";

    public VisitController(CacheService cache) {
        this.cache = cache;
    }

    @GetMapping("/visit")
    public ResponseEntity<Long> visit() {
        Long count = cache.increment(VISIT_KEY);
        return ResponseEntity.ok(count);
    }
}

Each call to /api/visit atomically increments site:visit:count in Redis, returning the updated total.

5. Working with Objects via RedisTemplate

When you need to store richer data structures, RedisTemplate<K, V> gives you full control over serialization.
A common pattern is to serialize values as JSON using Jackson, while keeping keys as plain strings.

5.1. JSON Serializer Configuration

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // JSON serializer for values
        Jackson2JsonRedisSerializer<Object> jsonSerializer =
                new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(
                LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL);
        jsonSerializer.setObjectMapper(mapper);

        // String serializer for keys
        StringRedisSerializer stringSerializer = new StringRedisSerializer();

        template.setKeySerializer(stringSerializer);
        template.setHashKeySerializer(stringSerializer);
        template.setValueSerializer(jsonSerializer);
        template.setHashValueSerializer(jsonSerializer);

        template.afterPropertiesSet();
        return template;
    }
}

5.2. Sample POJO

public class User implements Serializable {
    private Long id;
    private String username;
    private String email;
    // getters and setters omitted for brevity
}

5.3. Service Layer

@Service
public class UserCacheService {

    private final RedisTemplate<String, Object> template;
    private static final String PREFIX = "user:";

    public UserCacheService(RedisTemplate<String, Object> template) {
        this.template = template;
    }

    public void save(User user) {
        String key = PREFIX + user.getId();
        template.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
    }

    public User get(Long id) {
        String key = PREFIX + id;
        Object obj = template.opsForValue().get(key);
        return obj instanceof User ? (User) obj : null;
    }

    public void delete(Long id) {
        template.delete(PREFIX + id);
    }
}

6. Common Pitfalls & Tuning Tips

Issue What to Check Suggested Fix
Connection timeouts spring.redis.timeout vs. server latency Increase timeout or adjust max-wait in the pool.
Serialization mismatches Multiple modules using different serializers Keep a single RedisTemplate per serialization strategy or inject dedicated beans.
Hot keys blocking High‑frequency counters or single‑point writes Use Redis’s atomic INCR/DECR, or shard the key space, or employ Lua scripts for compound operations.
Data loss Relying solely on RDB snapshots Enable AOF (appendonly yes) and schedule regular backups.
Monitoring gaps Lack of visibility into pool health Expose metrics via Spring Boot Actuator (/actuator/metrics/redis.*) or use Redis’s INFO command.

7. Takeaway

By following the steps above—adding the right dependencies, configuring the connection, choosing the appropriate template, and handling serialization—you can harness Redis’s speed and flexibility within a Spring Boot application.
With careful tuning of connection pools, serialization strategies, and persistence settings, the combination becomes a robust foundation for caching, session management, real‑time counters, and beyond.

Feel free to extend this setup with Redis features such as publish/subscribe, transactions, or Lua scripting to meet more advanced use cases.