美文网首页
SpringBoot + Ehcache之自定义Key生成策略

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

作者: 亓亓亓亓凌 | 来源:发表于2018-09-07 17:17 被阅读0次

    今天在项目启用了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;
    
    /**
     * <b><code>CustomKeyGenerator</code></b>
     * <p>
     * Description: custom key generator of spring cache.
     * <p>
     * <b>Creation Time:</b> 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;
    
    /**
     * <b><code>CustomCachingConfig</code></b>
     * <p>
     * Description: Custom Caching Config.
     * <p>
     * <b>Creation Time:</b> 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生成策略

          本文链接:https://www.haomeiwen.com/subject/zerfgftx.html