自定義key的CacheConfig源碼剖析

Spring cache的源碼版本:spring-context-5.0.9.RELEASE.jar

項(xiàng)目demo代碼:點(diǎn)我跳轉(zhuǎn)

先講自定義可以干嘛任斋,再講解源碼:
通過(guò)自定義cache config,可以用來(lái)設(shè)置自定義的過(guò)期時(shí)間崔泵,自定義的序列化方式挂滓,自定義前綴等等嫉髓。@Cacheable 注解不能設(shè)置過(guò)期時(shí)間倘零,這點(diǎn)是由于cache本身是抽象,各種實(shí)現(xiàn)過(guò)期時(shí)間的一些具體緩存框架可能有差異幻梯,不過(guò)我覺(jué)得這是一個(gè)非常不爽的點(diǎn)兜畸。
所以我們來(lái)閱讀源代碼吧。

Cache啟動(dòng)初始化

AbstractCacheManager類中有一個(gè)cacheMap變量存儲(chǔ)所有的緩存實(shí)現(xiàn)碘梢,在項(xiàng)目初始化時(shí)咬摇,由于類中實(shí)現(xiàn)了InitializingBean接口,所有會(huì)初始化緩存煞躬,代碼:

    public abstract class AbstractCacheManager implements CacheManager, InitializingBean {

    private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);

    private volatile Set<String> cacheNames = Collections.emptySet();

    @Override
    public void afterPropertiesSet() {
        initializeCaches();
    }

    /**
     * Initialize the static configuration of caches.
     * <p>Triggered on startup through {@link #afterPropertiesSet()};
     * can also be called to re-initialize at runtime.
     * @since 4.2.2
     * @see #loadCaches()
     */
    public void initializeCaches() {
        // 1??重點(diǎn)在loadCaches方法
        Collection<? extends Cache> caches = loadCaches();
        synchronized (this.cacheMap) {
            this.cacheNames = Collections.emptySet();
            this.cacheMap.clear();           
            Set<String> cacheNames = new LinkedHashSet<>(caches.size());
            for (Cache cache : caches) {
                String name = cache.getName();
                this.cacheMap.put(name, decorateCache(cache));
                cacheNames.add(name);
            }
            this.cacheNames = Collections.unmodifiableSet(cacheNames);
        }
    }
}

由于loadCaches方法是抽象的肛鹏,我們實(shí)現(xiàn)使用的redis實(shí)現(xiàn),所有直接查看org.springframework.data.redis.cache.RedisCacheManager類的實(shí)現(xiàn)恩沛,閱讀源代碼發(fā)現(xiàn):

public class RedisCacheManager extends AbstractTransactionSupportingCacheManager {
...
    private final Map<String, RedisCacheConfiguration> initialCacheConfiguration;
...
    @Override
    protected Collection<RedisCache> loadCaches() {
        //1??可以看到實(shí)際上就是取initialCacheConfiguration變量的值
        List<RedisCache> caches = new LinkedList<>();
        for (Map.Entry<String, RedisCacheConfiguration> entry : initialCacheConfiguration.entrySet()) {
            //2??初始化cache
            caches.add(createRedisCache(entry.getKey(), entry.getValue()));
        }
        return caches;
    }
    protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
        return new RedisCache(name, cacheWriter, cacheConfig != null ? cacheConfig : defaultCacheConfig);
    }
...    
}    

通過(guò)注入自定義的cacheConfig能夠使不同的key擁有不同的cache配置在扰,達(dá)到自定義的效果。

Cache被調(diào)用

回到上面的正題雷客,在cacheManager初始化完成后芒珠,當(dāng)有請(qǐng)求來(lái)到@Cacheable注解處的方法時(shí),會(huì)通過(guò)aop代理的形式做invoke佛纫,頂層是在CacheAspectSupport的execute方法進(jìn)行代理妓局,

中間一個(gè)步驟省略,它最后會(huì)直接通過(guò)CacheManager去獲取cache呈宇,方法為:

public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
...
    @Override
    @Nullable
    public Cache getCache(String name) {
        Cache cache = this.cacheMap.get(name);
        if (cache != null) {
            return cache;
        }
        else {
            // Fully synchronize now for missing cache creation...
            synchronized (this.cacheMap) {
                cache = this.cacheMap.get(name);
                if (cache == null) {
                    cache = getMissingCache(name);
                    if (cache != null) {
                        cache = decorateCache(cache);
                        this.cacheMap.put(name, cache);
                        updateCacheNames(name);
                    }
                }
                return cache;
            }
        }
    }
...
}

我們查看下RedisCache內(nèi)部調(diào)用生成緩存的方法來(lái)看一下。

public class RedisCache extends AbstractValueAdaptingCache {
    @Override
    public void put(Object key, @Nullable Object value) {
        Object cacheValue = preProcessCacheValue(value);
...
        //1?? 過(guò)期時(shí)間是通過(guò)cacheConfig配置進(jìn)行獲取的局雄。
        cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl());
    }
    protected byte[] serializeCacheValue(Object value) {

        if (isAllowNullValues() && value instanceof NullValue) {
            return BINARY_NULL_VALUE;
        }
        //2?? value的序列化方式也是通過(guò)cacheConfig配置來(lái)初始化的
        return ByteUtils.getBytes(cacheConfig.getValueSerializationPair().write(value));
    }
}

自定義CacheConfig的配置方法

    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.builder(connectionFactory);
        builder.withInitialCacheConfigurations(customCacheConfig());
        return builder.build();
    }

    private Map<String, RedisCacheConfiguration> customCacheConfig() {
        Map<String, RedisCacheConfiguration> map = new HashMap<>();
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)).serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))

PS: 感覺(jué)使用Spring cache還是略麻煩甥啄,不如自己實(shí)現(xiàn)一個(gè)基于aop的cache吧。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末炬搭,一起剝皮案震驚了整個(gè)濱河市蜈漓,隨后出現(xiàn)的幾起案子穆桂,更是在濱河造成了極大的恐慌,老刑警劉巖融虽,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件享完,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡有额,警方通過(guò)查閱死者的電腦和手機(jī)般又,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)巍佑,“玉大人茴迁,你說(shuō)我怎么就攤上這事∮┧ィ” “怎么了堕义?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)脆栋。 經(jīng)常有香客問(wèn)我倦卖,道長(zhǎng),這世上最難降的妖魔是什么椿争? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任糖耸,我火速辦了婚禮,結(jié)果婚禮上丘薛,老公的妹妹穿的比我還像新娘嘉竟。我一直安慰自己,他們只是感情好洋侨,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布舍扰。 她就那樣靜靜地躺著,像睡著了一般希坚。 火紅的嫁衣襯著肌膚如雪边苹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,443評(píng)論 1 302
  • 那天裁僧,我揣著相機(jī)與錄音个束,去河邊找鬼。 笑死聊疲,一個(gè)胖子當(dāng)著我的面吹牛茬底,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播获洲,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼阱表,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起最爬,我...
    開(kāi)封第一講書(shū)人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤涉馁,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后爱致,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體烤送,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年糠悯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帮坚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡逢防,死狀恐怖叶沛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情忘朝,我是刑警寧澤灰署,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站局嘁,受9級(jí)特大地震影響溉箕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悦昵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一肴茄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧但指,春花似錦寡痰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至剩岳,卻和暖如春贞滨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拍棕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工晓铆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绰播。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓骄噪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親幅垮。 傳聞我的和親對(duì)象是個(gè)殘疾皇子腰池,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理尾组,服務(wù)發(fā)現(xiàn)忙芒,斷路器示弓,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 本文基于《Spring實(shí)戰(zhàn)(第4版)》所寫(xiě)。 啟用對(duì)緩存的支持 Spring對(duì)緩存的支持有兩種方式: 注解驅(qū)動(dòng)的緩...
    陽(yáng)光的技術(shù)小棧閱讀 1,455評(píng)論 0 1
  • 大腦就會(huì)預(yù)設(shè)一些條件呵萨,用來(lái)幫助我們奏属,對(duì)信息進(jìn)行處理和認(rèn)知。 這些預(yù)設(shè)的條件潮峦,就是「認(rèn)知框架」囱皿。 本質(zhì)上,人的一切思...
    方方不方呀閱讀 1,988評(píng)論 0 0
  • 周末兩天因?yàn)槲业氖韬龀类冢R走前忘了給銅錢(qián)草加水嘱腥。今早一進(jìn)辦公室我就看到,這盆長(zhǎng)勢(shì)旺盛的銅錢(qián)草拘悦,全都耷拉著腦...
    瑾子寶貝閱讀 403評(píng)論 0 1