DEV Community

Mustafa Karatas
Mustafa Karatas

Posted on

Spring Boot - Redis

Docker Compose File

Here is the basic docker-compose redis configuration

services:
    redis:
    image: redis:latest
    restart: always
    ports:
      - "6379:6379"
    environment:
      - REDIS_PASSWORD=my-password
      - REDIS_PORT=6379
      - REDIS_DATABASES=16
Enter fullscreen mode Exit fullscreen mode

Maven dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Application yml file

spring:
  cache:
    type: redis
    redis:
      host: localhost
      port: 6379

cache:
  config:
    entryTtl: 60
    jwtToken:
      entryTtl: 30
Enter fullscreen mode Exit fullscreen mode

In application yml file, cache type and redis host, port informations are defined.
Redis config class

@Configuration
@EnableCaching
@Slf4j
public class RedisConfig {

    @Value("${spring.cache.redis.host}")
    private String redisHost;

    @Value("${spring.cache.redis.port}")
    private int redisPort;

    @Bean
    public LettuceConnectionFactory redisConnectionFactory() {
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisHost, redisPort);
        configuration.setPassword("my-password");
        log.info("Connected to : {} {}", redisHost, redisPort);

        return new LettuceConnectionFactory(configuration);
    }

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        return RedisCacheManager.create(connectionFactory);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(){
        final RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new GenericToStringSerializer<Object>(Object.class));
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }
}
Enter fullscreen mode Exit fullscreen mode

Working with cache annotations

To enable caching in your application, you can use the @EnableCaching annotation and then annotate methods that should be cached with @Cacheable, @CachePut, and @CacheEvict

@GetMapping("/product/{id}")  
@Cacheable(value = "product", key = "#id")
public Product getProductById(@PathVariable long id) {...}
Enter fullscreen mode Exit fullscreen mode

1. @Cacheable is employed to fetch data from the database, storing it in the cache. Upon future invocations, the method retrieves the cached value directly, eliminating the need to execute the method again.

The value attribute establishes a cache with a specific name, while the key attribute permits the use of Spring Expression Language to compute the key dynamically. Consequently, the method result is stored in the ‘product’ cache, where respective ‘product_id’ serves as the unique key. This approach optimizes caching by associating each result with a distinct key.

2. @CachePut is used to update data in the cache when there is any update in the source database.

@PutMapping("/product/{id}")
@CachePut(cacheNames = "product", key = "#id")
public Product editProduct(@PathVariable long id, @RequestBody Product product) {...}
Enter fullscreen mode Exit fullscreen mode

3. @CacheEvict is used for removing stale or unused data from the cache.

@DeleteMapping("/product/{id}")
@CacheEvict(cacheNames = "product", key = "#id", beforeInvocation = true)
public String removeProductById(@PathVariable long id) {...}
Enter fullscreen mode Exit fullscreen mode

We use cacheName and key to remove specific data from the cache. The beforeInvocation attribute allows us to control the eviction process, enabling us to choose whether the eviction should occur before or after the method execution.

@DeleteMapping("/product/{id}")
@CacheEvict(cacheNames = "product", allEntries = true)
public String removeProductById(@PathVariable long id) {...}
Enter fullscreen mode Exit fullscreen mode

Alternatively, all the data can also be removed for a given cache by using the allEntries attribute as true. The annotation allows us to clear data for multiple caches as well by providing multiple values as cacheName.

4. @Caching is used for multiple nested caching on the same method.

@PutMapping("/{id}")
@Caching(
     evict = {@CacheEvict(value = "productList", allEntries = true)},
     put = {@CachePut(value = "product", key = "#id")}
)
public Product editProduct(@PathVariable long id, @RequestBody Product product) {...}
Enter fullscreen mode Exit fullscreen mode

As Java doesn’t allow multiple annotations of the same type to be declared for a method, doing so will generate a compilation error. We can group different annotations into Caching, as shown.

5. @CacheConfig is used for centralized configuration.

@CacheConfig(cacheNames = "product")
public class ProductController {...}
Enter fullscreen mode Exit fullscreen mode

Working with RedisTemplate

You can use the RedisTemplate to interact with Redis. For example, to save data in Redis:

@Autowired
private RedisTemplate<String, Object> redisTemplate;

public void saveData(String key, Object data) {
    redisTemplate.opsForValue().set(key, data);
}
Enter fullscreen mode Exit fullscreen mode

Retrieve data from Redis

public Object getData(String key) {
    return redisTemplate.opsForValue().get(key);
}
Enter fullscreen mode Exit fullscreen mode

Example service class for redis template

@Service
public class CacheTokenService {

    private final StringRedisTemplate stringRedisTemplate;
    private final RedisTemplate<String, Object> redisTemplate;

    public CacheTokenService(StringRedisTemplate stringRedisTemplate, RedisTemplate<String, Object> redisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.redisTemplate = redisTemplate;
    }

    public void saveData(String key, Object data) {
        redisTemplate.opsForValue().set(key, data);
    }

    public Object getData(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public void cacheToken(String username, String token) {
        stringRedisTemplate
        .opsForValue()
        .set("token:" + username, token, Duration.ofMinutes(60));
    }

    public String getCachedToken(String username) {
        // Retrieve the token from Redis cache
        return stringRedisTemplate
        .opsForValue()
        .get("token:" + username);
    }

}
Enter fullscreen mode Exit fullscreen mode

Redis GUI : RedisInsight

Download link : https://redis.io/insight/

Top comments (0)

The discussion has been locked. New comments can't be added.