SpringBoot整合 redis key (过期、新增、修改)的三种方式,看这篇就够了

news2024/11/22 21:10:40

文章目录

  • 原理
  • 关于 *notify-keyspace-events*
  • 关于redis的消息主题(Topic)
  • 重写监听
  • 容器注册
  • 自定义解析
  • 常见整合问题
  • 鸣谢

文章主要描述了Springboot整合key变化的三种方式,同时列出了一些整合坑点与概念

原理

SpringBoot整合Redis key变化的原理就是万变不离其宗,简单点就是:
spring-boot-starter-data-redis + notify-keyspace-events

关于 notify-keyspace-events

  • notify-keyspace-events AKEx 是 Redis 中的一个命令,用于配置服务器发送的通知类型。这里的参数 AKEx 代表的是键空间通知和键事件通知。

  • 具体来说,A 表示接收所有类型的通知,K 表示接收键空间通知,Ex 表示接收键事件通知。键空间通知是关于整个数据库的变化,而键事件通知是关于特定键的变化。

  • 举个例子,如果你在 Redis 中执行了 SET mykey "Hello" 命令,那么使用了 notify-keyspace-events AKEx 配置的客户端将会接收到一个关于 mykey 键的键事件通知。

  • 需要注意的是,要使用 notify-keyspace-events 命令,必须在 Redis 服务器中启用相关的 notify 机制,否则客户端无法接收到任何通知。同时,该命令只能在 Redis 的 string 类型键的值被修改时才会发送通知,其他类型键(如 hash、list、set、sorted set 等)的修改不会触发通知。

关于redis的消息主题(Topic)

Redis 消息主题(Topic)是用于发布和订阅消息的关键字。根据 Redis 的设计,它只支持发布/订阅模型的消息,而不支持请求/响应模型的消息。

在 Redis 中,可以使用 PSUBSCRIBE 命令来订阅一个或多个主题,并监听相关的消息。以下是一些常见的 Redis 消息主题:

  • __keyevent@*__:expired:过期事件主题,发布所有库过期消息,*表示所有。
  • __keyevent@0__:expired:过期事件主题,发布db0库过期消息0代表db0
  • __keyevent@1__:del:当使用 DEL 命令删除一个键时触发的事件。
  • __keyevent@4__:rename:当使用 RENAME 命令重命名一个键时触发的事件。
  • __keyevent@5__:set:当使用 SET 命令设置一个键的值时触发的事件。

这些主题是在 Redis 4.0 版本中引入的,用于表示键的特定事件。通过订阅相应的主题,可以监听相关的事件并进行相应的处理。
除了以上列举的主题外,Redis 还支持自定义的主题,用户可以根据自己的需求来定义和订阅相关的主题。

ok,在了解上面概念后我们直接上代码看下重写监听的方式吧

重写监听

  1. 开启redis key变化事件
    redis配置文件配置 notify-keyspace-events AKEx ,默认是关闭的
  2. 引入依赖(其他正常的依赖省略了,记得添加哈)
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
  1. 写个RedisListenerConfig 配置文件(文件名随便取,不一定要跟博主一样)


@Configuration
public class RedisListenerConfig {
	//配置redis监听容器
    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        return container;
    }
    //配置redis的序列化策略
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);//所有属性均可见
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);//为null不参加序列化
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//在Redis中存储对象类信息
        jackson2JsonRedisSerializer.setObjectMapper(mapper);
        template.setKeySerializer(stringRedisSerializer);
        template.setValueSerializer(jackson2JsonRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.setConnectionFactory(factory);
        return template;
    }
}
  1. 写个RedisKeyExpirationListener监听器
@Component
@Slf4j
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    public RedisKeyExpirationListener(RedisMessageListenerContainer redisMessageListenerContainer) {
        super(redisMessageListenerContainer);
    }

    /**
     * 针对redis数据失效事件,进行数据处理
     * @param message message must not be {@literal null}. 过期的key
     * @param pattern pattern matching the channel (if specified) - can be {@literal null}. 队列名称
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // 拿到key
        String expiredKey = message.toString();
        log.info("监听Redis key过期,key:{},channel:{}", expiredKey, new String(pattern));
    }
}

到此就完成了key过期监听,那这种方式怎么做key更新和删除呢

KeyExpirationEventMessageListener 该类是Springboot封装的过期监听类,我们看下源码。

在这里插入图片描述

但是Springboot可没有跟你封装更新和删除的哦。所以我们要学会举一反三。

  • 第一步复制KeyExpirationEventMessageListener,假设名字是KeyUpdateEventMessageListener
  • 修改__keyevent@0__:expired__keyevent@0__:set 这个是更新的topic
  • 写个RedisKeyUpdateListener extent KeyUpdateEventMessageListener,重写onMessage方法

ok,写完了,插个tips。Python开发的文件类型转化windows工具,支持png,jpeg,ico等文件类型互转

我们继续看下容器注册方式

容器注册

上面的配置就不重写了

  1. 注意我们写个 RedisKeyUpdatedListener implements MessageListener
@Component
@Slf4j
public class RedisKeyUpdatedListener implements MessageListener {

    /**
     * key 更新监听
     */
    @Override
    public void onMessage(Message message, byte[] pattern) {
        // 拿到key
        String expiredKey = message.toString();
        log.info("监听Redis keyg更新,key:{},channel:{}", expiredKey, new String(pattern));
    }
}
  1. 然后修改下容器配置
@Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        //监听指定db0 的key set事件 *表示监听所有的db
        container.addMessageListener(redisKeyUpdatedListener, new PatternTopic("__keyevent@*__:set"));
        return container;
    }

这里需要注意下redisKeyUpdatedListener 是通过注入方式注入的,不是new,因为如果通过new的方式。监听器有业务逻辑时会引入多个业务service组件。通过new的方式就只能通过构造的方式传入,而且service组件是从配置类注入的。

多个的话如下

container.addMessageListener(redisKeyUpdatedListener, new PatternTopic("__keyevent@*__:set"));
container.addMessageListener(redisKeyExpiredListener, new PatternTopic("__keyevent@*__:expired"));
container.addMessageListener(redisKeyDelListener, new PatternTopic("__keyevent@*__:del"));

自定义解析

这个就比较方便了。直接看代码吧,但耦合度有点高,不符合设计模式规范

@Component
public class CustomRedisMessageListener implements MessageListener {
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @Override
    public void onMessage(Message message, byte[] pattern) {
        String ops = new String(message.getBody());     //操作
        String channel = new String(message.getChannel());
        String key = channel.split(":")[1];
		//对redis的新增或删除事件进行监听
        if ("set".equals(ops)) {
            String value = redisTemplate.opsForValue().get(key);
            handleSet(key, value);
        } else if ("del".equals(ops)) {
            handleDel(key);
        }
    }

    /**
     * 监听新增 处理逻辑
     */
    private void handleSet(String key, String value) {
			//将数据同步刷新到内存中
            gatewayCache.refreshApiWhitelistsCache(id, JsonUtil.toObject(value, Set.class));
    }

    /**
     * 监听删除 处理逻辑
     * @param key 被删除的key
     */
    private void handleDel(String key) { 
            gatewayCache.deleteApiWhitelists(id);
    }
}

常见整合问题

为啥我引入包,代码也无比的正确,为啥key过期了就是监听不到呢

  • 确保项目能启动
  • 确保依赖是否冲突了
  • 确保redis配置开启了 notify-keyspace-events AKEx

为啥我配置了notify-keyspace-events 。就是没有监听到key 更新事件呢?

  • 确保配置的是 notify-keyspace-events AKEx,而不是 notify-keyspace-events Ex。ex只能监听到过期事件,而监听不到删除事件

鸣谢

  • 非常感谢你从头到尾阅读了这篇文章,希望其中的内容对你有所启发和帮助。如果你还有其他问题或需要进一步的了解,欢迎随时关注我的动态并留言
  • 最后希望大家给作者点个关注和小赞赞支持下,创作不易啊
  • 觉得有收藏价值也可以进行收藏
  • 最后给大家来波小tips。优雅封装接口给第三方调用

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二叉树的非递归遍历实现(三种)

1、先序遍历 先序遍历使用了栈的结构&#xff0c;先压入根节点&#xff0c;然后依次将其右子节点和左字节点压入。然后就可以实现“头左右”的遍历顺序 /*** 先序遍历*/public static void pre_order(TreeNode treeNode){if (treeNode null){return;}Stack<TreeNode> …

PAT 1136 A Delayed Palindrome

个人学习记录&#xff0c;代码难免不尽人意 A B C where A is the original number, B is the reversed A, and C is their sum. A starts being the input number, and this process ends until C becomes a palindromic number – in this case we print in the last line …

Graylog 更改显示的时区(Display timezone)

每个 Graylog 用户都可以配置他们的显示时区。 这会更改用于查看日志消息的时区&#xff0c;但不会更改日志消息的原始时区。 默认情况下&#xff0c;Graylog 显示 UTC 格式的所有时间戳&#xff08;也就是 0:00&#xff09;。就像是下面这样 非Admin账户要更改时区&#xff1…

防御网络攻击风险的4个步骤

如今&#xff0c;人们正在做大量工作来保护 IT 系统免受网络犯罪的侵害。令人担忧的是&#xff0c;对于运营技术系统来说&#xff0c;情况却并非如此&#xff0c;运营技术系统用于运行从工厂到石油管道再到发电厂的所有业务。 组织应该强化其网络安全策略&#xff0c;因为针对…

ConsoleApplication815项目(直接加载+VEH Hook Load)

上线图 ConsoleApplication815.cpp #include <iostream> #include<Windows.h> #include "detours.h" #include "detver.h" #pragma comment(lib,"detours.lib")#pragma warning(disable:4996)LPVOID Beacon_address; SIZE_T Beacon…

统计教程|PASS实现单因素多水平方差分析的样本含量估计

前面我们讲过当主要结局指标是连续变量时&#xff0c;两总体均数比较时样本量估计的计算公式原理以及PASS软件操作教程。当设计研究的试验因素只有一个&#xff0c;并且该因素的水平数&#xff08;组数&#xff09;k≥3&#xff0c;当主要研究指标为连续变量时我们常用单因素多…

设计模式—原型模式(Prototype)

目录 一、什么是原型模式&#xff1f; 二、原型模式具有什么优缺点吗&#xff1f; 三、有什么缺点&#xff1f; 四、什么时候用原型模式&#xff1f; 五、代码展示 ①、简历代码初步实现 ②、原型模式 ③、简历的原型实现 ④、深复制 ⑤、浅复制 一、什么是原型模式&…

2023-8-28 树的重心(树与图的深度优先遍历)

题目链接&#xff1a;树的重心 #include <cstring> #include <iostream> #include <algorithm>using namespace std;const int N 100010, M N * 2;int n; int h[N], e[M], ne[M], idx; int ans N; bool st[N];void add(int a, int b) {e[idx] b, ne[id…

小鹏接手MONA,滴滴造了一台什么样的车?

作者|张祥威 编辑|德新 8月28日&#xff0c;小鹏汽车宣布和滴滴出行达成战略合作。 除了资本层面的合作&#xff0c;双方合作的业务核心是代号「MONA」的车型项目。 根据协议&#xff1a; 双方将打造一款售价15万元级别的A级纯电动轿车&#xff0c;项目代号MONA&#xff1b…

5.Redis-string

string 字符串 字符串类型是 Redis 最基础的数据类型&#xff0c;关于字符串需要特别注意&#xff1a; 1.⾸先Redis中所有 key 的类型都是字符串类型&#xff0c;⽽且其他⼏种数据结构也都是在字符串类似基础上构建的&#xff0c;例如 list 和 set 的元素类型是字符串类型。 2…

遥遥领先?实际是落后两代以上,小丑挡不住更多消费者买iPhone

谈到国产手机的时候&#xff0c;谁都知道一个品牌&#xff0c;都说遥遥领先苹果&#xff0c;然而事实上呢所有安卓手机都落后苹果两代&#xff0c;正是这样的现实让国内消费者越来越多买iPhone&#xff0c;推动苹果在中国高端手机市场逼近八成份额。 1.苹果为何领先&#xff1f…

Android12之ABuffer数据处理(三十五)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

WebGL:开始学习 / 理解 WebGL / WebGL 需要掌握哪些知识 / 应用领域 / 前端值得学WebGL吗

一、WebGL发展史 2006 年&#xff0c;WebGL 的发展史可以追溯到 2006 年左右&#xff0c;当时 Mozilla Foundation 的一个开发人员 Vladimir Vukićević 开始尝试在 Firefox 浏览器中嵌入 OpenGL&#xff0c;为 JavaScript 提供底层图形库的支持。随后&#xff0c;这个项目引…

IDEA插件推荐 - Grep Console - 控制台日志过滤的插件

装上该插件之后&#xff0c;我们就可以很方便的进行日志的过滤、筛选。

周鸿祎为360智脑招贤纳士;LLM时代的选择指南;Kaggle大语言模型实战;一文带你逛遍LLM全世界 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 思否「齐聚码力」黑客马拉松&#xff0c;用技术代码让生活变得更美好 主页&#xff1a;https://pages.segmentfault.com/google-hacka…

智通三千亮相2023中国软博会

“软件赋智&#xff0c;数实融合。”8月20日—23日&#xff0c;2023中国国际软件产品和信息服务交易博览会在南京举办。软博会连续举办19届。期间&#xff0c;《2023年我国工业软件产业发展研究报告》《中国软件产业高质量发展紫金指数&#xff08;2023&#xff09;》等发布。 …

c++查漏补缺(1)

目录 1.explicit关键字 2.static关键字 3.友元函数 1.explicit关键字 exeplicit关键字是在构造函数要使用的关键字。可以防止“隐式构造”&#xff0c;例如&#xff1a; #include<iostream>using namespace std;class Date { public:explicit Date(int year, int mo…

【科研论文配图绘制】task5 SciencePlots绘图包入门

【科研论文配图绘制】task5 SciencePlots绘图包入门 task5主要学习了SciencePlots拓展包的出图样式&#xff0c;掌握SciencePlots的安装及具体使用。 SciencePlots作为一个专门用于科研论文绘图的第三方拓展工具包&#xff0c;提供了主流英文科技 期刊(如 Nature、Science 和 …

1、监测数据采集物联网应用开发步骤(1)

项目介绍 本文章编写目的针对下图中《。。。解决方案》所涉及的开发资料&#xff1b; 监测数据采集物联网应用解决方案_yong427的博客-CSDN博客 开发步骤实现从0开始搭建软件框架&#xff0c;该开发步骤基于python3.0语言及相关工具实现&#xff0c;阅读本文章之前请先初步百…

MyBatis学习简要

目录 什么是MyBatis? MyBatis实现的设想 MyBatis基于配置文件的开发步骤 mybatis的配置文件 Mapper代理开发 配置文件完成增删改查的三步 注解开发 一、条件查询 参数接收时&#xff0c;参数的设置&#xff1a; 动态条件查询&#xff1a; 二、添加功能 步骤&#xf…