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

在这里插入图片描述

– 求知若饥,虚心若愚。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/661587.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【开源三方库】Aki:一行代码极简体验JSC++跨语言交互

一、简介 OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;的前端开发语言是ArkTS&#xff0c;在TypeScript&#xff08;简称TS&#xff09;生态基础上做了进一步扩展&#xff0c;继承了TS的所有特性&#xff0c;是JavaScript&#xff08;简称JS&#xf…

大模型时代的具身智能系列专题(五)

stanford宋舒然团队 宋舒然是斯坦福大学的助理教授。在此之前&#xff0c;他曾是哥伦比亚大学的助理教授&#xff0c;是Columbia Artificial Intelligence and Robotics Lab的负责人。他的研究聚焦于计算机视觉和机器人技术。本科毕业于香港科技大学。 主题相关作品 diffusio…

MySQL之创建高性能的索引(六)

创建高性能的索引 选择合适的索引列顺序 当使用前缀索引的时候&#xff0c;在某些条件值的基数比正常值高的时候&#xff0c;问题就来了。例如&#xff0c;在某些应用程序中&#xff0c;对于没有登录的用户&#xff0c;都将其用户名记录为"guest"&#xff0c;在记录…

OpenMV学习笔记2——颜色识别

目录 一、打开单颜色识别实例代码 二、代码基础部分 三、阈值选择 四、给识别到的颜色画框 五、多颜色识别 一、打开单颜色识别实例代码 如图&#xff0c;双击打开对应文件即可进入实例代码。 二、代码基础部分 # Single Color RGB565 Blob Tracking Example # # This e…

MindSpore实践图神经网络之环境篇

MindSpore在Windows11系统下的环境配置。 MindSpore环境配置大概分为三步&#xff1a;&#xff08;1&#xff09;安装Python环境&#xff0c;&#xff08;2&#xff09;安装MindSpore&#xff0c;&#xff08;3&#xff09;验证是否成功 如果是GPU环境还需安装CUDA等环境&…

浅谈 parallelStream和Stream 源码及其应用场景

上篇讲述了list.forEach()和list.stream().forEach() 异同点 谈到了并行流的概念&#xff0c;本篇则从源码出发&#xff0c;了解一下其原理。 一、流的初始操作流程 jdk8中 将Collection中加入了转换流的概念。 default Stream<E> stream() {return StreamSupport.str…

Verilog HDL基础知识(一)

引言&#xff1a;本文我们介绍Verilog HDL的基础知识&#xff0c;重点对Verilog HDL的基本语法及其应用要点进行介绍。 1. Verilog HDL概述 什么是Verilog&#xff1f;Verilog是IEEE标准的硬件描述语言&#xff0c;一种基于文本的语言&#xff0c;用于描述最终将在硬件中实现…

2024 angstromCTF re 部分wp

Guess the Flag 附件拖入ida 比较简单&#xff0c;就一个异或 switcher 附件拖入ida 明文flag Polyomino 附件拖入ida 需要输入九个数&#xff0c;然后进入处理和判断&#xff0c;如果满足条件则进入输出flag部分&#xff0c;flag和输入有关&#xff0c;所以要理解需要满足什么…

202474读书笔记|《我自我的田渠归来》——愿你拥有向上的力量,一切的好事都应该有权利发生

202474读书笔记|《我自我的田渠归来》——愿你拥有向上的力量 《我自我的田渠归来》作者张晓风&#xff0c;被称为华语散文温柔的一支笔&#xff0c;她的短文很有味道&#xff0c;角度奇特&#xff0c;温柔慈悲而敏锐。 很幸运遇到了这本书&#xff0c;以她的感受重新认识一些事…

ChatGPT的基本原理是什么?又该如何提高其准确性?

在深入探索如何提升ChatGPT的准确性之前&#xff0c;让我们先来了解一下它的工作原理吧。ChatGPT是一种基于深度学习的自然语言生成模型&#xff0c;它通过预训练和微调两个关键步骤来学习和理解自然语言。 在预训练阶段&#xff0c;ChatGPT会接触到大规模的文本数据集&#x…

转发和重定向

目录 是什么 转发&#xff08;Forwarding&#xff09; 概念 特点 实现方式 重定向&#xff08;Redirecting&#xff09; 概念 特点 实现方式 转发和重定向区别整理 转发和重定向的适用场景 转发&#xff08;Forwarding&#xff09; 重定向&#xff08;Redirect&am…

反转!Greenplum 还在,快去 Fork 源码

↑ 关注“少安事务所”公众号&#xff0c;欢迎⭐收藏&#xff0c;不错过精彩内容~ 今早被一条消息刷爆群聊&#xff0c;看到知名开源数仓 Greenplum 的源码仓“删库跑路”了。 要知道 GP 新东家 Broadcom 前几日才刚刚免费开放了 VMware Workstation PRO 17 和 VMware Fusion P…

【本地运行chatgpt-web】启动前端项目和service服务端项目,也是使用nodejs进行开发的。两个都运行成功才可以使用!

1&#xff0c;启动web界面 https://github.com/Chanzhaoyu/chatgpt-web#node https://nodejs.org/en/download/package-manager # 使用nvm 安装最新的 20 版本。 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash source /root/.bashrc n…

stm32学习-CubeIDE使用技巧

1.hex文件生成 右键工程 2.仿真调试 3.常用快捷键 作用快捷键代码提示alt/代码注释/反注释ctrl/ 4.项目复制 复制项目&#xff0c;将ioc文件名改为项目名即可图形化编辑

开源一个工厂常用的LIMS系统

Senaite是一款强大且可靠的基于Web的LIMS/LIS系统&#xff0c;采用Python编写&#xff0c;构建在Plone CMS基础架构之上。该系统处于积极开发阶段&#xff0c;在灵活的定制空间中为开发人员提供了丰富的功能。其中&#xff0c;Senaite在处理REST的JSON API上做得出色&#xff0…

【Javascript系列】Terser除了压缩代码之外,还有优化代码的功能

什么是Terser 前端开发的小伙伴一定不陌生&#xff0c;经常用这个工具进行代码压缩。有一种说法是Uglify-es的替代品。作为Javascript的解析器和压缩器&#xff0c;已经得到了开发人员的广泛使用。 可以优化代码 今天一个偶然的机会&#xff0c;在写一个删除功能的确认框&am…

系统架构设计师【第3章】: 信息系统基础知识 (核心总结)

文章目录 3.1 信息系统概述3.1.1 信息系统的定义3.1.2 信息系统的发展3.1.3 信息系统的分类3.1.4 信息系统的生命周期3.1.5 信息系统建设原则3.1.6 信息系统开发方法 3.2 业务处理系统&#xff08;TPS&#xff09;3.2.1 业务处理系统的概念3.2.2 业务处理系统的功能 …

Element-UI 入门指南:从安装到自定义主题的详细教程

Element-UI 是一个基于 Vue.js 的前端组件库&#xff0c;它提供了丰富的 UI 组件&#xff0c;可以帮助开发者快速构建高质量的用户界面。以下是使用 Element-UI 的快速入门指南&#xff1a; 安装 Element-UI Element-UI 是一个基于 Vue.js 的组件库&#xff0c;它提供了丰富的…

【Python】解决Python报错:TypeError: %d format: a number is required, not str

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

DETR整体模型结构解析

DETR流程 Backbone用卷积神经网络抽特征。最后通过一层1*1卷积转化到d_model维度fm&#xff08;B,d_model,HW&#xff09;。 position embedding建立跟fm维度相同的位置编码(B&#xff0c;d_model,HW&#xff09;。 Transformer Encoder,V为fm&#xff0c;K&#xff0c;Q为fm…