Search code examples
javaredisspring-dataspring-data-redis

Spring Redis issue: GetAllCacheNames from redis cache is not working with RedisCacheManager


Hi below is my redis cache configuration, and I am trying to get all the cachename stored on redis server using:

redisCacheManager.getCacheNames()

but it doesnot gives me the cacheName present in my redis server.

I prefix cacheName using Cachable annotation: @Cacheable("cacheName")

I have 2 questions here?

1) Why I am not able to get the cacheNames which i stored in redis server. 2)How can i dynamically create the prefix cacheName since i don't want to write seperate method for all of them?

@Bean
JedisConnectionFactory jedisConnectionFactory() {
    JedisConnectionFactory factory = new JedisConnectionFactory();
    factory.setHostName(redisHost);
    factory.setPort(redisPort);
    factory.setUsePool(true);
    return factory;
}

@Bean
RedisTemplate<Object, Object> redisTemplate() {
    RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
    redisTemplate.setConnectionFactory(jedisConnectionFactory());
    redisTemplate.setDefaultSerializer(new StringRedisSerializer());
   // redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
    return redisTemplate;
}

@Bean
CacheManager cacheManager() {
    // configuration to set the time to expire in seconds, messageCache is name of method
    Map<String,Long> cacheMap = new HashMap<String, Long>();
    //cacheMap is the name of the map where we put all the method names for which we want time to expire.
    RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate());
    redisCacheManager.setUsePrefix(true);
    //redisCacheManager.setExpires(cacheMap);
    return redisCacheManager;
}

Solution

  • funtoos's answer above does show the correct way to display the cache names. For the cache names to be returned by the CacheManager.getCacheNames() method, they need to exist. With redis as the cache, just using the @Cacheable annotation on a method, like @Cacheable("testCache"), doesn't create a cache config named testCache till the annotated method is accessed the first time. As that method most probably wouldn't be accessed till bean initialization is complete, that cache name wouldn't be returned by the getCacheNames() method at initialization time. So, to address the original use case(setting different expiration times for different caches), the simplest way would be to define all the cache names and their corresponding expiration times(and any other config that needs to be customized) using a RedisCacheManagerBuilderCustomizer bean.

    Updated, working version of the config from the question, with a RedisCacheManagerBuilderCustomizer bean replacing the CacheManager bean along with a logger to log cache names(and some replacements for since deprecated methods), is below:

    package io.github.devatherock.config;
    
    import java.time.Duration;
    
    import javax.annotation.PostConstruct;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
    import org.springframework.cache.CacheManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.redis.cache.RedisCacheConfiguration;
    import org.springframework.data.redis.cache.RedisCacheWriter;
    import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
    import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
    import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    
    import lombok.extern.slf4j.Slf4j;
    
    @Configuration
    public class RedisConfig {
    
        @Bean
        public JedisConnectionFactory jedisConnectionFactory() {
            RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
            config.setHostName("localhost");
            config.setPort(6379);
    
            JedisClientConfiguration clientConfig = JedisClientConfiguration
                    .builder()
                    .usePooling()
                    .build();
    
            return new JedisConnectionFactory(config, clientConfig);
        }
    
        @Bean
        public RedisTemplate<Object, Object> redisTemplate() {
            RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
            redisTemplate.setConnectionFactory(jedisConnectionFactory());
            redisTemplate.setDefaultSerializer(new StringRedisSerializer());
    
            return redisTemplate;
        }
        
        @Bean
        public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
            return (builder) -> builder
              .withCacheConfiguration("testCache",
                RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(5)))
              .withCacheConfiguration("messageCache",
                RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(1000L)))
              .cacheWriter(RedisCacheWriter.nonLockingRedisCacheWriter(jedisConnectionFactory()));
        }
        
        @Slf4j
        @Configuration
        public static class CacheNamesLogger {
            
            @Autowired
            private CacheManager cacheManager;
            
            @PostConstruct
            public void init() {
                cacheManager.getCacheNames().forEach(cacheName -> {
                    LOGGER.info("Cache: {}", cacheName);
                });
            }
        }
    }
    

    During app initialization time, the logger does log both the cache names correctly.

    21:44:42.661 [main] INFO  i.g.d.c.RedisConfig$CacheNamesLogger - Cache: testCache
    21:44:42.662 [main] INFO  i.g.d.c.RedisConfig$CacheNamesLogger - Cache: messageCache
    

    The complete application can be found on github.