spring cache設置指定Key過期時間

今天是2019年最後一天,回想年初立下的小目標,貌似都完成的不理想-_- 還得繼續努力啊!!!生活還在繼續,加油。

最近剛好在使用spring cache做緩存的時候,有需要針對不同的key設置過期時間的場景,找了下資料,實現這個功能,做個總結。

spring cache 集成redis是基於spring-data-redis組件開發的一直通過註解就能輕鬆實現redis緩存操作的框架。
但原生的spring cache不支持緩存過期,默認都是沒有過期時間的,以下實現自定義緩存過期時間。

spring-data-redis版本是1.8.11,所以需要使用此版本或者兼容此版本的其他版本。

先看spring的RedisCacheManager類代碼:

	protected RedisCache createCache(String cacheName) {
		long expiration = computeExpiration(cacheName);
		return new RedisCache(cacheName, (usePrefix ? cachePrefix.prefix(cacheName) : null), redisOperations, expiration,
				cacheNullValues);
	}

	protected long computeExpiration(String name) {
		Long expiration = null;
		if (expires != null) {
			expiration = expires.get(name);
		}
		return (expiration != null ? expiration.longValue() : defaultExpiration);
	}

其中expiration變量其實就是過期時間(單位是秒),如果我們不做任何事情,那麼expiration 就是defaultExpiration,這個值是0,也就是永不過期。所以我們可以從這個入手,自定義一個RedisCacheManager,覆蓋createCache方法。

自定義類:CustomizerRedisCacheManager

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * @Description RedisCacheManager 
 * @Author huangd
 * @Date 2019-12-31 16:09
 **/
@Slf4j
public class CustomizerRedisCacheManager extends RedisCacheManager {

    private static final char SEPARATOR = '#';  // 過期時間分隔符,可以用其他符號

    public CustomizerRedisCacheManager(RedisOperations redisOperations) {
        super(redisOperations);
    }

    @Override
    protected RedisCache createCache(String cacheName) {
        long defaultExpiration = computeExpiration(cacheName);
        int expireIndex = cacheName.indexOf(SEPARATOR);
        if (expireIndex > 0) {
            defaultExpiration = getExpirationTime(cacheName, expireIndex, defaultExpiration);
            cacheName = cacheName.substring(0, expireIndex);
        }

        return new RedisCache(cacheName, (isUsePrefix() ? getCachePrefix().prefix(cacheName) : null),
                getRedisOperations(), defaultExpiration);
    }

    /**
     * 緩存時間
     * @param name cacheName cache#3600
     * @param expireIndex
     * @param defaultExpiration 默認過期時間
     * @return
     */
    protected long getExpirationTime(String name, int expireIndex, long defaultExpiration) {
        String expirationAsString = name.substring(expireIndex + 1);
        try {
            Long expiration = NumberUtils.toLong(expirationAsString, defaultExpiration);
            return expiration.longValue();
        } catch (Exception e) {
            log.error("獲取指定cacheName:{},緩存失效時間異常:{}", name, e.getMessage());
        }

        return defaultExpiration;
    }

}

設置redis的key序列化

@Configuration
public class CustomCachingConfigurerSupport extends CachingConfigurerSupport {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    public CustomizerRedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
        CustomizerRedisCacheManager redisCacheManager = new CustomizerRedisCacheManager(redisTemplate);
        redisCacheManager.setUsePrefix(true); // 寫入redis中保留cacheName前綴
        return redisCacheManager;

    }
}

使用@Cacheable驗證緩存失效時間:

@Cacheable(value = "ota.vehicle.series#20", key = "#k + '_' + 123")
    public String testExpire(String k) {
        return "test expire";
    }

緩存20秒後過期,效果如下:
在這裏插入圖片描述
20秒後過期,key被刪除
在這裏插入圖片描述

這裏需要注意一點:因爲cacheName帶上了#20,這樣寫到redis中也會帶上這個前綴,所以需要去掉這個前綴,上面CustomizerRedisCacheManager 類中cacheName = cacheName.substring(0, expireIndex);
就是將此部分截斷再寫入。

發佈了42 篇原創文章 · 獲贊 16 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章