Redis 自定义注解 key动态设置过期时间 Springboot

通过对value的值的约定分割实现动态设置过期时间

@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

    @Value("${spring.cache.entryTtl:3600}")
    private Long entryTtl;

    private static final StringRedisSerializer STRING_SERIALIZER = new StringRedisSerializer();

    private static final RedisSerializer JSON_SERIALIZER = new GenericFastJsonRedisSerializer();

    private static final RedisSerializationContext.SerializationPair<String> STRING_PAIR =
            RedisSerializationContext.SerializationPair.fromSerializer(STRING_SERIALIZER);

    private static final RedisSerializationContext.SerializationPair<Object> JSON_PAIR =
            RedisSerializationContext.SerializationPair.fromSerializer(JSON_SERIALIZER);

    private final RedisConnectionFactory redisConnectionFactory;

    public RedisCacheConfig(RedisConnectionFactory redisConnectionFactory) {
        this.redisConnectionFactory = redisConnectionFactory;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // set key serializer
        // 设置key序列化类,否则key前面会多了一些乱码
        template.setKeySerializer(STRING_SERIALIZER);
        template.setHashKeySerializer(STRING_SERIALIZER);

        template.setValueSerializer(JSON_SERIALIZER);
        template.setHashValueSerializer(JSON_SERIALIZER);
        // 如果 KeySerializer 或者 ValueSerializer 没有配置,则对应的 KeySerializer、ValueSerializer 才使用这个 Serializer
        template.setDefaultSerializer(JSON_SERIALIZER);

        // factory
        template.setConnectionFactory(redisConnectionFactory);
        template.afterPropertiesSet();
        return template;
    }

    @Override
    public CacheErrorHandler errorHandler() {
        return new RedisCacheErrorHandler();
    }

    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (o, method, objects) -> {
            StringBuilder sb = new StringBuilder(32);
            sb.append(o.getClass().getSimpleName());
            sb.append(".");
            sb.append(method.getName());
            if (objects.length > 0) {
                sb.append("#");
            }
            String sp = "";
            for (Object object : objects) {
                sb.append(sp);
                if (object == null) {
                    sb.append("NULL");
                } else {
                    sb.append(object.toString());
                }
                sp = ".";
            }
            return sb.toString();
        };
    }

    @Bean
    @Override
    public CacheManager cacheManager() {
        // 初始化一个RedisCacheWriter
        RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);

        // 设置默认过期时间:1 分钟
        RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
                .entryTtl(Duration.ofSeconds(entryTtl))
                // 使用注解时的序列化、反序列化
                .serializeKeysWith(STRING_PAIR).serializeValuesWith(JSON_PAIR);
          //返回自定义CacheManager
        return new CusRedisCacheManager(cacheWriter, defaultCacheConfig);
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(STRING_SERIALIZER);
        redisTemplate.setValueSerializer(STRING_SERIALIZER);
        return redisTemplate;
    }
}
//实现
public class CusRedisCacheManager extends RedisCacheManager {
    private final RedisCacheWriter cacheWriter;

    private final RedisCacheConfiguration defaultCacheConfig;

    /**
     * 用于返回自定义的redisCache
     **/
    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
        return new CusRedisCache(name, cacheWriter, cacheConfig != null ? cacheConfig : defaultCacheConfig);

    }

    public CusRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
        super(cacheWriter, defaultCacheConfiguration);
        this.cacheWriter = cacheWriter;
        this.defaultCacheConfig = defaultCacheConfiguration;
    }
}
@Slf4j
public class CusRedisCache extends RedisCache {

    private RedisCacheWriter redisCacheWriter;
    private RedisCacheConfiguration configuration;
    /**
     * 校验规则:获取时间
     */
    private final static String REGEX_STR = ".*\\#\\d+$";

    private static final String SPLITTER = "#";

    /**
     * Create new {@link RedisCache}.
     *
     * @param name        must not be {@literal null}.
     * @param cacheWriter must not be {@literal null}.
     * @param cacheConfig must not be {@literal null}.
     */
    protected CusRedisCache(String name, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig) {
        super(name, cacheWriter, cacheConfig);
        redisCacheWriter = cacheWriter;
        configuration = cacheConfig;
    }


    @Override
    public synchronized <T> T get(Object key, Callable<T> valueLoader) {
        if (key == null) {
            log.error("redis cache key can not be null");
            return null;
        }
        return super.get(key, valueLoader);
    }

    /**
     * 重写cache put 逻辑,引入自定义TTL 实现
     * 实现逻辑:
     * 1.通过获取@Cacheable 中的value ,然后根据约定好的特殊字符进行分割
     * 2.从分割结果集中获取设置的TTL 时间并将value 中的,然后给当前缓存设置TTL
     *
     * @param key
     * @param value
     */
    @Override
    public void put(Object key, Object value) {
        String name = super.getName();
        //是否按照指定的格式
        if (Pattern.matches(REGEX_STR, name)) {
            putWithExpireTime(name, key, value);
        } else {
            //原来逻辑处理
            super.put(key, value);
        }
    }

    public void putWithExpireTime(String name, Object key, @Nullable Object value) {
        List<String> keyList = Arrays.asList(name.split(SPLITTER));
        //获取键值
        String finalName = keyList.get(0);
        //获取TTL 执行时间
        Long ttl = Long.valueOf(keyList.get(1));

        //获取缓存value
        Object cacheValue = preProcessCacheValue(value);
        //获取value 为null 时,抛出异常
        if (!isAllowNullValues() && cacheValue == null) {
            log.error(String.format("Cache '%s' does not allow 'null' values. Avoid storing null via '@Cacheable" + "(unless" +
                    "=\"#result == null\")' " + "or configure RedisCache to allow 'null' via " + "RedisCacheConfiguration.",
                    name));
            return;
        }
        //插入时添加时间
        redisCacheWriter.put(finalName, serializeCacheKey(createCacheKey(key)), serializeCacheValue(cacheValue),
                Duration.ofSeconds(ttl));
    }

    /**
     * @描述 现有key 值格式为  key#ttl ;改方法将key 值后边的#ttl 去掉 ;例如test# 10;改方法处理后为test
     */
    @Override
    protected String createCacheKey(Object key) {
        String convertedKey = convertKey(key);
        if (!configuration.usePrefix()) {
            return convertedKey;
        }
        return prefixCacheKey(convertedKey);
    }


    private String prefixCacheKey(String key) {
        String name = super.getName();
        if (Pattern.matches(REGEX_STR, name)) {
            List<String> keyList = Arrays.asList(name.split(SPLITTER));
            String finalName = keyList.get(0);
            return configuration.getKeyPrefixFor(finalName) + key;
        }
        // allow contextual cache names by computing the key prefix on every call.
        return configuration.getKeyPrefixFor(name) + key;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值