Spring cache abstraction using Redis


1. Overview

This post will focus on integrating the Redis with the Spring Boot application to leverage the declarative annotation based caching support provided by the Spring cache abstraction.

2. Add Redis dependency to the application

Start by adding the Redis dependency to the build script file - build.gradle

compile('org.springframework.boot:spring-boot-starter-data-redis')

3. Redis Configuration class

To make the Spring resolve the caches by annotation, extend the CachingConfigurerSupport class and annotate the config class with @EnableCaching.

@Configuration
@EnableCaching
public class RedisConfiguration extends CachingConfigurerSupport {...}
3.1 Redis client

Jedis is one of the popular Redis Java client, configure the JedisConnectionFactory which will create Jedis instances for connecting to the Redis server.

  @Bean
  public JedisConnectionFactory jedisConnectionFactory() {
    JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
    jedisConnectionFactory.setHostName("127.0.0.1");
    jedisConnectionFactory.setPort(6379);
    jedisConnectionFactory.setUsePool(true);
    return jedisConnectionFactory;
  }
3.2 RedisTemplate

Create a RedisTemplate instance which helps to serialize/deserialize between the object and binary data on the Redis store.

Here StringRedisSerializer is used for serializing the key and GenericJackson2JsonRedisSerializer for the value. This template is a generified one, it can be wired to multiple components and reused as it’s thread-safe.

  @Bean
  public StringRedisSerializer stringRedisSerializer() {
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    return stringRedisSerializer;
  }

  @Bean
  public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisJsonSerializer() {
    GenericJackson2JsonRedisSerializer genericJackson2JsonRedisJsonSerializer =
        new GenericJackson2JsonRedisSerializer();
    return genericJackson2JsonRedisJsonSerializer;
  }

  @Bean
  public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
    redisTemplate.setConnectionFactory(jedisConnectionFactory());
    redisTemplate.setExposeConnection(true);
    redisTemplate.setKeySerializer(stringRedisSerializer());
    redisTemplate.setValueSerializer(genericJackson2JsonRedisJsonSerializer());
    return redisTemplate;
3.3 RedisCacheManager

The cache abstraction does not provide an actual store and relies on abstraction materialized by the org.springframework.cache.Cache and org.springframework.cache.CacheManager interfaces. RedisCacheManager is the implimentation of the CacheManager for Redis.

  @Bean
  public RedisCacheManager cacheManager() {
    RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate());
    redisCacheManager.setTransactionAware(true);
    redisCacheManager.setLoadRemoteCachesOnStartup(true);
    redisCacheManager.setUsePrefix(true);
    return redisCacheManager;
  }

4. Annotating the methods

For caching declaration, the abstraction provides a set of Java annotations:

4.1 @Cacheable

Triggers cache population

    @Cacheable(value = "whitePaper", key = "#id")
    public WhitePaper findWhitePaperById(String id) 
    {
        return repository.findById(id);
    }
4.2 @CachePut

Updates the cache without interfering with the method execution

    @CachePut(value = "whitePaper", key = "#whitePaper?.id")
    public WhitePaper updateWhitePaper(WhitePaper whitePaper)
    {
        return repository.update(whitePaper);
    }
4.3 @CacheEvict

Triggers cache eviction

    @CacheEvict(value = "whitePaper", key = "#id.toString()")
    public WhitePaper saveWhitePaper(int id){
        return repository.delete(id);
    }

5. Conclusion

Redis is not a simple key-value store, it can be called as a data structure store as it’s can store data in advanced data structures. Spring Cache abstraction is a high level abstraction for interacting with the store.