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;

/** * <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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM