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

今天在項(xiàng)目啟用了ehcache緩存,但是某些方法使用緩存后不能正確的返回?cái)?shù)據(jù),拋出了類型轉(zhuǎn)換異常,找了一番資料后發(fā)現(xiàn)是緩存的key生成策略問(wèn)題,在此將此問(wèn)題及解決辦法記錄一下。

spring cache緩存的key默認(rèn)是通過(guò)KeyGenerator生成的,其默認(rèn)生成策略如下:

  • 如果方法沒有參數(shù),則使用0作為key。
  • 如果只有一個(gè)參數(shù)的話則使用該參數(shù)作為key。
  • 如果參數(shù)多于一個(gè)的話則使用所有參數(shù)的hashCode作為key。

可以看出默認(rèn)的key生成策略中并沒有涉及方法名稱和類,這就意味著如果我們有兩個(gè)參數(shù)列表相同的方法,我們用相同的參數(shù)分別調(diào)用兩個(gè)方法,當(dāng)調(diào)用第二個(gè)方法的時(shí)候,spring cache將會(huì)返回緩存中的第一個(gè)方法的緩存值,因?yàn)樗麄兊膋ey是一樣的。下面我們看一段代碼:

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

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

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

}

場(chǎng)景:當(dāng)我們先調(diào)用了getModel1(1),ehcache就會(huì)將方法的返回結(jié)果以"1"為key放入緩存中,當(dāng)我們?cè)僬{(diào)用getModel2(1)時(shí),ehcache就會(huì)從緩存中找key為"1"的數(shù)據(jù)(即 Model1 )并試圖將它轉(zhuǎn)換為Model2 ,這就出現(xiàn)了異常: Model1 can not be cast to Model2.....

所以我們需要自定義key策略來(lái)解決這個(gè)問(wèn)題,將類名和方法名和參數(shù)列表一起來(lái)生成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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,680評(píng)論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,819評(píng)論 18 399
  • 緩存是最直接有效提升系統(tǒng)性能的手段之一。個(gè)人認(rèn)為用好用對(duì)緩存是優(yōu)秀程序員的必備基本素質(zhì)。 本文結(jié)合實(shí)際開發(fā)經(jīng)驗(yàn),從...
    Java小生閱讀 977評(píng)論 1 3
  • 今年,梁鶴譽(yù)種了一棵小葫蘆,還沒有成熟的時(shí)候,她就說(shuō)等葫蘆熟了就賣葫蘆。這幾天,她都在出售自己的葫蘆。小手里拿著一...
    向日葵3閱讀 264評(píng)論 0 1
  • 上一節(jié)說(shuō)完了配置文件的加載順序,那么本節(jié)就來(lái)看一下struts.xml文件中各配置項(xiàng)的含義和說(shuō)明。該文件是Stru...
    d03bd8f89ce7閱讀 792評(píng)論 0 50

友情鏈接更多精彩內(nèi)容