Spring Boot with Redis
Redis is an in-memory data store — lightning fast. Use it for caching, session storage, rate limiting, and pub/sub messaging.
Setup
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
docker run -d --name bookstore-redis -p 6379:6379 redis:7
spring:
data:
redis:
host: localhost
port: 6379
cache:
type: redis
redis:
time-to-live: 600000 # 10 minutes
@Cacheable — Method-Level Caching
@SpringBootApplication
@EnableCaching
public class BookstoreApiApplication { }
@Service
public class BookService {
@Cacheable(value = "books", key = "#id")
public BookResponse findById(Long id) {
// This method is called only on cache MISS
log.info("Fetching book from database: {}", id);
Book book = bookRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Book", id));
return BookResponse.from(book);
}
@Cacheable(value = "booksByAuthor", key = "#author")
public List<BookResponse> findByAuthor(String author) {
return bookRepository.findByAuthor(author).stream()
.map(BookResponse::from).toList();
}
@CacheEvict(value = "books", key = "#id")
public BookResponse update(Long id, UpdateBookRequest request) {
// Evicts cached entry when book is updated
Book book = bookRepository.findById(id).orElseThrow();
book.setTitle(request.title());
return BookResponse.from(bookRepository.save(book));
}
@CacheEvict(value = {"books", "booksByAuthor"}, allEntries = true)
public void clearCache() {
log.info("All caches cleared");
}
@CachePut(value = "books", key = "#result.id()")
public BookResponse create(CreateBookRequest request) {
// Always executes AND updates cache
Book book = bookRepository.save(new Book(request.title(), request.author()));
return BookResponse.from(book);
}
}
| Annotation | Behavior |
|---|---|
@Cacheable |
Return cached value if exists, else execute and cache |
@CacheEvict |
Remove from cache |
@CachePut |
Execute and update cache (always runs) |
RedisTemplate — Direct Access
@Service
public class RateLimitService {
private final StringRedisTemplate redisTemplate;
public RateLimitService(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public boolean isAllowed(String clientIp, int maxRequests, Duration window) {
String key = "rate:" + clientIp;
Long count = redisTemplate.opsForValue().increment(key);
if (count == 1) {
redisTemplate.expire(key, window);
}
return count <= maxRequests;
}
}
Redis for Session Storage
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
spring:
session:
store-type: redis
redis:
namespace: bookstore:sessions
timeout: 30m
Sessions are now stored in Redis — works across multiple app instances (horizontal scaling).
Redis Configuration
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisCacheConfiguration cacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(10))
.disableCachingNullValues()
.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}
Key Takeaways
@EnableCaching+@Cacheable= transparent method caching.@CacheEvictremoves stale data;@CachePutforces update.RedisTemplatefor direct key-value operations (rate limiting, counters).- Redis sessions enable horizontal scaling — session shared across instances.
- Always set TTL — cached data should expire.
What’s Next?
Next: Spring Security — authentication, authorization, and securing your API.