Spring Cache自定义缓存key和过期时间的实现代码

 更新时间:2024年05月30日 11:06:20   作者:Charge8  
使用 Redis的客户端 Spring Cache时,会发现生成 key中会多出一个冒号,而且有一个空节点的存在,查看源码可知,这是因为 Spring Cache默认生成key的策略就是通过两个冒号来拼接,本文给大家介绍了Spring Cache自定义缓存key和过期时间的实现,需要的朋友可以参考下

一、自定义全局缓存key和双冒号替换

使用 Redis的客户端 Spring Cache时,会发现生成 key中会多出一个冒号,而且有一个空节点的存在。

查看源码可知,这是因为 Spring Cache默认生成key的策略就是通过两个冒号来拼接。

在这里插入图片描述

同时 Spring Cache缓存到 Redis的 key为:Cache注解的value|cacheNames的值与其 key的值的拼接。

在这里插入图片描述

我们可以自定义 CacheKeyPrefix来替换双冒号,也可以自定义全局缓存 key的前缀。

    /**
     * 项目名
     */
    private final static String SPRING_APPLICATION_NAME = "ws";

    /**
     * Cache 默认的 key前缀为空,key的格式为(@Cacheable注解上的信息): value|cacheNames::key。
     * 自定义需求:
     * 1、key前缀分隔符:: 不习惯,换成:前缀分隔符。
     * 2、在 Cache相关注解 key的生成规则上,添加全局缓存 key的前缀。
     */
    private static final CacheKeyPrefix CUSTOM_CACHE_KEY_PREFIX = cacheName -> SPRING_APPLICATION_NAME + ":" + cacheName0 + ":";

二、自定义过期时间

CacheManager 是 Spring 各种缓存的抽象接口。抽象的意义在于屏蔽不同实现细节的差异和提供扩展性。

对于 Spring Cache的缓存注解,原生没有额外提供一个指定 ttl 的配置,它是不支持在注解上添加过期时间的。

实际的业务场景中,如果希望通过缓存注解指定过期时间TTL,我们就需要自定义 RedisCacheManager来完成。

自定义TTL约定:

1、支持使用 Cache注解的value|cacheNames来自定义过期时间。#ttlOfSecond不作为key的一部分。

示例:value|cacheNames = “keyName#ttlOfSecond”。 keyName为业务缓存key。#为自定义TTL连接符。ttlOfSecond为过期时间,单位秒。

2、Spring Cache缓存到 Redis的 key需要过滤掉 #ttlOfSecond这部分。

实现逻辑步骤:

  • 1、自定义缓存管理器并继承RedisCacheManager,同时重写createRedisCache方法
  • 2、将默认的缓存管理器改成我们自定义的缓存管理器

1、自定义缓存管理器

/**
 * 自定义 RedisCacheManager配置。
 */
@Slf4j
public class CustomRedisCacheManager extends RedisCacheManager {

    /**
     * 项目名
     */
    private final static String SPRING_APPLICATION_NAME = "ws";

    /**
     * 自定义缓存参数的TTL分隔符
     * 示例:value|cacheNames = “keyName#ttlOfSecond”。
     */
    private static final String CUSTOM_TTL_SEPARATOR = "#";

    public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
        super(cacheWriter, defaultCacheConfiguration);
    }

    /**
     * @param name        must not be {@literal null}. 业务 Cache注解的value|cacheNames
     * @param cacheConfig can be {@literal null}.
     * @return
     */
    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
        Duration ttl = getTtlByCustomName(name);
        if (ttl == null) {
            // 如果自定义 TTL为空,则设置全局 TTL为7天。
            ttl = Duration.ofDays(7);
        }
        /**
         * Cache缓存配置
         */
        cacheConfig = cacheConfig
                .computePrefixWith(CUSTOM_CACHE_KEY_PREFIX) // 设置缓存key
                .entryTtl(ttl)  // 设置缓存的过期时间,查询不会更新过期时间
        ;
        return super.createRedisCache(name, cacheConfig);
    }

    /**
     * Cache 默认的 RedisKey的格式为(@Cacheable注解上的信息): value|cacheNames::key。
     * 自定义需求:
     * 1、key前缀分隔符:: 不习惯,换成:前缀分隔符。
     * 2、在 Cache相关注解 key的生成规则上,添加全局缓存 key的前缀。
     */
    private static final CacheKeyPrefix CUSTOM_CACHE_KEY_PREFIX = cacheName -> {
        // 过滤掉自定义的 TTL分隔符
        String cacheName0 = cacheName.split(CUSTOM_TTL_SEPARATOR)[0];
        return SPRING_APPLICATION_NAME + ":" + cacheName0 + ":";
    };
    

    /**
     * 根据 TTL分隔符拆分字符串,并进行过期时间 TTL的解析
     *
     * @param name 业务 Cache注解的value|cacheNames
     * @return
     */
    private Duration getTtlByCustomName(String name) {
        if (StringUtils.isBlank(name)) {
            return null;
        }
        /**
         * 根据 TTL分隔符拆分字符串,并进行过期时间 TTL的解析
         * 数组元素0 = 缓存的名称
         * 数组元素1 = 缓存过期时间TTL
         */
        String[] cacheParams = name.split(CUSTOM_TTL_SEPARATOR);
        if (cacheParams.length > 1) {
            // 如果 TTL解析异常或者小于等于0,则返回null;
            Long ttl = null;
            try {
                ttl = Long.parseLong(cacheParams[1]);
            } catch (NumberFormatException e) {
                log.debug(" CacheManager 解析自定义 TTL异常,e.getMessage = {}", e.getMessage());
            }
            if (ttl != null && ttl > 0) {
                return Duration.ofSeconds(ttl);
            }
        }
        return null;
    }
}

2、注入自定义缓存管理器

在自定义的 CacheConfiguration类中,注入我们自定义的缓存管理器。

@EnableCaching
@Configuration
public class CacheConfiguration {

     @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
         // 初始化一个RedisCacheWriter
         RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
         // 初始化一个RedisCacheConfiguration
         RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
         // 返回一个自定义的CacheManager
         return new CustomRedisCacheManager(redisCacheWriter, defaultCacheConfig);
    }

}

3、业务使用

    @Cacheable(value = "userCache_#120", key = "#id", unless = "#result==null")
    //@Cacheable(value = "userCache_", key = "#id", unless = "#result==null")
    //@Cacheable(value = "userCache_#0asa", key = "#id", unless = "#result==null")
    @Override
    public UserDTO getById(Long id) {
        if (id == null || id <= 0L) {
            return null;
        }
        UserDO userDO = userMapper.selectById(id);
        return do2DTO(userDO);
    }

在这里插入图片描述

以上就是Spring Cache自定义缓存key和过期时间的实现代码的详细内容,更多关于Spring Cache缓存key和过期时间的资料请关注脚本之家其它相关文章!

相关文章

  • java 求解二维数组列最小值

    java 求解二维数组列最小值

    这篇文章主要介绍了java 求解二维数组列最小值的相关资料,需要的朋友可以参考下
    2017-05-05
  • SpringBoot中注册过滤器的几种实现方式

    SpringBoot中注册过滤器的几种实现方式

    本文主要介绍了SpringBoot中注册过滤器的几种实现方式,主要介绍了三种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-01-01
  • 如何对jdk版本升级或降级

    如何对jdk版本升级或降级

    这篇文章主要介绍了如何对jdk版本升级或降级方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java内存分布归纳整理详解

    Java内存分布归纳整理详解

    这篇文章主要介绍了java程序运行时内存分布详解,需要的朋友可以参考下
    2017-04-04
  • java设计模式学习之简单工厂模式

    java设计模式学习之简单工厂模式

    这篇文章主要为大家详细介绍了java设计模式学习之简单工厂模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • SpringBoot日志框架之Log4j2快速入门与参数详解

    SpringBoot日志框架之Log4j2快速入门与参数详解

    本文介绍了SpringBoot日志框架log4j2的基本使用和配置方法,包括将日志输出到控制台、文件、Elasticsearch和Kafka,多个输出目的地的配置,异步日志记录器的使用以及log4j2.xml配置文件的详细语法和参数含义,需要的朋友可以参考下
    2023-05-05
  • SpringBoot 整合Security权限控制的初步配置

    SpringBoot 整合Security权限控制的初步配置

    这篇文章主要为大家介绍了SpringBoot 整合Security权限控制的初步配置实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • IDEA使用Maven创建父与子多模块项目的图文教程

    IDEA使用Maven创建父与子多模块项目的图文教程

    在 IntelliJ IDEA 中使用 Maven 创建父与子多模块项目是一个常见的开发实践,有助于更好地组织和管理代码,所以本文小编给大家介绍了IDEA使用Maven创建父与子多模块项目的图文教程,需要的小伙伴跟着小编一起来看看吧
    2025-03-03
  • 详解Spring中的AOP及AspectJ五大通知注解

    详解Spring中的AOP及AspectJ五大通知注解

    这篇文章主要介绍了详解Spring中的AOP及AspectJ五大通知注解,AOP面向切面编程是一种新的方法论,是对传统OOP面向对象编程的补充,AOP 的主要编程对象是切面(aspect),切面模块化横切关注点,需要的朋友可以参考下
    2023-08-08
  • 详解Mybatis核心类SqlSessionFactory的构建

    详解Mybatis核心类SqlSessionFactory的构建

    这篇文章主要为大家详细介绍了Mybatis核心类SqlSessionFactory的构建过程,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-12-12

最新评论