Spring cache sets the specified key expiration time

Today is the last day of 2019. Looking back on the small goals set at the beginning of the year, it seems that they were all not ideal -_- You have to continue working hard! ! ! Life is still going on, come on.

Recently, when I was using spring cache for caching, there were scenarios where it was necessary to set the expiration time for different keys. I found the information to implement this function and make a summary.

The spring cache integrated redis is a framework developed based on the spring-data-redis component that has been able to easily realize the redis cache operation through annotations.
But the native spring cache does not support cache expiration. By default, there is no expiration time. The following implements a custom cache expiration time.

The spring-data-redis version is 1.8.11, so you need to use this version or other versions compatible with this version.

First look at spring's RedisCacheManager class code:

	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);
	}

The expiration variable is actually the expiration time (in seconds). If we don't do anything, then expiration is defaultExpiration. This value is 0, which means it will never expire. So we can start from this, customize a RedisCacheManager, and override the createCache method.

Custom class: 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;
    }

}

Set redis key serialization

@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;

    }
}

Use @Cacheable to verify the cache expiration time:

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

The cache expires after 20 seconds, the effect is as follows: After
Insert picture description here
20 seconds expires, the key is deleted
Insert picture description here

One thing to note here: because cacheName has #20, this prefix will also be added to redis, so you need to remove this prefix. In the CustomizerRedisCacheManager class above, cacheName = cacheName.substring(0, expireIndex);
is this part Truncate and write again.

Guess you like

Origin blog.csdn.net/huangdi1309/article/details/103784115