SpringBoot + Ehcache之自定义Key生成策略

今天在项目启用了ehcache缓存,但是某些方法使用缓存后不能正确的返回数据,抛出了类型转换异常,找了一番资料后发现是缓存的key生成策略问题,在此将此问题及解决办法记录一下。

spring cache缓存的key默认是通过KeyGenerator生成的,其默认生成策略如下:

  • 如果方法没有参数,则使用0作为key。
  • 如果只有一个参数的话则使用该参数作为key。
  • 如果参数多于一个的话则使用所有参数的hashCode作为key。

可以看出默认的key生成策略中并没有涉及方法名称和类,这就意味着如果我们有两个参数列表相同的方法,我们用相同的参数分别调用两个方法,当调用第二个方法的时候,spring cache将会返回缓存中的第一个方法的缓存值,因为他们的key是一样的。下面我们看一段代码:

@CacheConfig(cacheNames = "default")
public class SampleService {

  @Cacheable
  public Model1 getModel1(Integer id) {
    return // ...
  }

  @Cacheable
  public Model2 getModel2(Integer id) {
    return // ...
  }

}

场景:当我们先调用了getModel1(1),ehcache就会将方法的返回结果以"1"为key放入缓存中,当我们再调用getModel2(1)时,ehcache就会从缓存中找key为"1"的数据(即 Model1 )并试图将它转换为Model2 ,这就出现了异常: Model1 can not be cast to Model2.....

所以我们需要自定义key策略来解决这个问题,将类名和方法名和参数列表一起来生成key,下面是自定义的Key生成代码:

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * CustomKeyGenerator
 * 

* Description: custom key generator of spring cache. *

* Creation Time: 2018/9/6 16:46 * * @date 2018/9/6 * @since JDK 1.7 */ @Configuration public class CustomKeyGenerator implements KeyGenerator { @Override public Object generate(Object target, Method method, Object... params) { return new CustomKey(target.getClass(), method.getName(), params); } /** * Like {@link org.springframework.cache.interceptor.SimpleKey} but considers the method. */ static final class CustomKey { private final Class clazz; private final String methodName; private final Object[] params; private final int hashCode; /** * Initialize a key. * * @param clazz the receiver class * @param methodName the method name * @param params the method parameters */ CustomKey(Class clazz, String methodName, Object[] params) { this.clazz = clazz; this.methodName = methodName; this.params = params; int code = Arrays.deepHashCode(params); code = 31 * code + clazz.hashCode(); code = 31 * code + methodName.hashCode(); this.hashCode = code; } @Override public int hashCode() { return this.hashCode; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof CustomKey)) { return false; } CustomKey other = (CustomKey) obj; if (this.hashCode != other.hashCode) { return false; } return this.clazz.equals(other.clazz) && this.methodName.equals(other.methodName) && Arrays.deepEquals(this.params, other.params); } } }

启用自定义的Key生成策略

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Configuration;

/**
 * CustomCachingConfig
 * 

* Description: Custom Caching Config. *

* Creation Time: 2018/9/6 17:14 * * @date 2018/9/6 * @since JDK 1.7 */ @Configuration public class CustomCachingConfig extends CachingConfigurerSupport { @Override public KeyGenerator keyGenerator() { return new CustomKeyGenerator(); } }

代码摘自:A Better Spring Cache KeyGenerator
参考资料:https://blog.csdn.net/u013378306/article/details/52168628

你可能感兴趣的:(SpringBoot + Ehcache之自定义Key生成策略)