10

I'm having the issue when my cache keys are colliding in Spring using the @Cacheable annotation. For instance, with the following two methods:

@Cacheable("doOneThing")
public void doOneThing(String name) {
  // do something with name
}

@Cacheable("doAnotherThing")
public void doAnotherThing(String name) {
  // do some other thing with name
}

Here is my cache configuration, in which I've added a keyGenerator and a cacheManager bean:

@Configuration
@EnableCaching
public class CacheConfig {

  @Bean
  public JedisConnectionFactory redisConnectionFactory() {
    return new JedisConnectionFactory();
  }

  @Bean
  public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
    RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
    redisTemplate.setConnectionFactory(cf);
    return redisTemplate;
  }

  @Bean
  public CacheManager cacheManager(RedisTemplate redisTemplate) {
    return new RedisCacheManager(redisTemplate);
  }

  @Bean
  public KeyGenerator keyGenerator() {
    return new KeyGenerator() {
      @Override
      public Object generate(Object o, Method method, Object... params) {
        StringBuilder sb = new StringBuilder();
        sb.append(o.getClass().getName());
        sb.append(method.getName());
        for (Object param : params) {
          sb.append(param.toString());
        }
        return sb.toString();
      }
    };
  }
}

For some reason, the cache key always gets set to the name parameter in the method, not the result of the keyGenerator.generate(..) method, causing both methods to return the same cache result.

I know that I can specify the key manually on each @Cacheable annotation, but that seems a little extensive for every method I'd like to cache.

Edit

I've noticed that setting the keyGenerator option inside of the @Cacheable annotation to the name of my bean resolves the issue, like so:

@Cacheable(value = "doOneThing", keyGenerator = "keyGenerator")
public void doOneThing(String name) {
  // do something with name
}

And setting the keyGenerator option in the @CacheConfig annotation on the class also resolves the issue. It seems that this shouldn't be necessary though. Am I missing something?

Stephane Nicoll
  • 31,977
  • 9
  • 97
  • 89
blacktide
  • 10,654
  • 8
  • 33
  • 53
  • If you pass a single argument to the `@Cacheable` annotation it is interpreted as the name of the cache to use. Did you _really_ want to be using two different caches? – Madbreaks Sep 28 '18 at 20:07

1 Answers1

10

Your configuration should implement CachingConfigurer (usually you would extend from CachingConfigurerSupport) to customize how caching works.

Stephane Nicoll
  • 31,977
  • 9
  • 97
  • 89
  • 2
    Thank you! Extending `CachingConfigurerSupport` in my `CacheConfig` class resolved the issue. – blacktide Dec 20 '14 at 15:27
  • You're welcome. It made me realize that we should probably be a bit more explicit about it. I'll see what I can do to update the documentation in that area. Thanks for raising this! – Stephane Nicoll Dec 22 '14 at 09:42
  • StephaneNicoll May i ask you why overriding the method after extending CachingConfigurer is not enough to let the system know what instances of CacheManager and KeyGenerator it has to use and instead we need to annotate the methods returning them with @Bean ? – FrancescoM Oct 18 '18 at 09:56
  • Please create your own question – Stephane Nicoll Nov 05 '18 at 15:13