《框架封装 · Redis 事件监听》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍
文章目录
- 写在前面的话
- 技术入门
- 实战分享
- 运用场景
- 总结陈词
写在前面的话
企业实战开发中,事件监听的运用场景非常多,当某事件发生的时候,会触发某个响应处理,其主要优势体现在多负载实例的场景下。与前几篇博文《知识点扫盲 · 监听器 Listener》《后端程序猿 · 基于 Lettuce 实现缓存容错策略》提到的观察者模式、发布订阅模式等,有异曲同工之妙。
本篇文章先介绍一下,框架封装人员如何处理事件监听场景,默认基于 RedisMessageListenerContainer实现,下面以此技术加以说明。
技术入门
【技术简介】
RedisMessageListenerContainer 是 Spring Data Redis 提供的一个类,用于异步处理 Redis 中的发布/订阅消息。它利用 Redis 的发布/订阅机制,通过消息通道(channel)或模式(pattern)订阅消息,并在消息到达时触发相应的监听器方法。该机制广泛应用于实时数据处理、消息广播等场景。
【使用入门】
Step1、引入 Maven 依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Step2、注册消息监听 Bean,订阅事件
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);container.setTaskExecutor(this.defaultTaskExecutor());Topic websocket = new ChannelTopic("websocket");Topic versionUpdate = new ChannelTopic("versionUpdate");List<Topic> list = new ArrayList<>();list.add(websocket);list.add(versionUpdate);WebsocketRedisMessageListener listener = new WebsocketRedisMessageListener();listener.setRedisTemplate(redisTemplate);container.addMessageListener(listener, list);return container;
}
Step3、实现监听消费逻辑
public class WebsocketRedisMessageListener implements MessageListener {@Overridepublic void onMessage(Message message, byte[] pattern) {try {String msgChannel = new String(pattern);String msgBody = (String) getRedisTemplate().getValueSerializer().deserialize(message.getBody());switch (msgChannel) {case TOPIC_VERSION:VersionSocket versionSocket = new VersionSocket();versionSocket.sendMessageAll(msgBody);break;default:LOGGER.warn("处理redis主题, 找不到对应的主题,{}", msgChannel);break;}} catch (Exception e) {LOGGER.error("处理redis事件失败:{}", ExceptionUtil.stacktraceToString(e));}}
}
Step4、按需发布事件
redisTemplate.convertAndSend("versionUpdate", JSON.toJSONString(versionUpdate));
【拓展说明】
通过 RedisMessageListenerContainer 还可以实现针对 Redis-Key 增删改以及过期的监听。
这不是本篇文章重点,详情搜索:KeyExpirationEventMessageListener、 PatternTopic 等关键词。
实战分享
设计思路:
技术基础入门介绍完了,功能可以实现,但是步骤略多,作为框架封装开发人员,肯定要帮忙加工一下,不可能放任各业务部门的开发人员随意添加,那可能出现各种奇葩问题,还需要架构人员兜底。
接下来分享一下实战经验:
1、事件监听的实现方式有多种,框架集成了 Redis 监听方式,作为事件总线模块的默认底层实现。如果想使用其他中间件来替代默认实现,也预留了接口,方便替换,Redis 监听实现的关键技术依然是RedisMessageListenerContainer
2、将消息监听器Bean的定义工作放到框架核心包处理,包含设定默认线程池等
3、提供快速使用消费功能的接口,开发人员只需要按规约实现接口即可完成订阅工作
4、提供发布消息的API,统一操作入口
下面贴一下代码,展示封装后,开发人员如何使用:
//订阅事件
public class PortalEventListener implements ZhanshenEventListener {/*** 订阅事件KEY*/public static final Set<String> PATTERN_KEY = Set.of("zhanshen.portal");@Overridepublic Set<String> patterns() {return PATTERN_KEY;}@Overridepublic void handleEvent(ZhanshenEvent zhanshenEvent) {log.info("收到事件消息,pattern:{},data:{} ", zhanshenEvent.getPattern(), zhanshenEvent.getData());}
}//发布事件
ZhanshenEventListener.publishEvent("zhanshen.portal", "测试事件消息");//补充:可以定义多个ZhanshenEventListener实现类,框架会统一帮忙触发。
题外话:注意事项
封装过程中,遇到一个小坑,分享一下:
RedisMessageListenerContainer 的默认使用线程池是SimpleAsyncTaskExecutor,每次消费都会创建一个线程来处理,这样就会有大量的新线程被创建。生产环境下建议使用自定义线程池,减少性能损耗。
运用场景
在实际开发中,每个后端服务都会有多个实例,在这种情况下,当一个接口触发的时候,需要所有实例都做出响应,那事件监听机制就非常有用了。
场景1:WebSocket 在线用户通知
博主所在公司采用WebSocket技术实现了统一门户工作站的消息通知推送功能,用户登录的时候,需要调用后端接口,存储在线用户列表数据,这时候可能信息存储在某一个实例中。
当需要给用户发通知的时候,需要拉取到所在后端的用户 Session,进行 WebSocket 的 send操作。这时候由于后端是多实例,有可能没有存储相关用户信息,这时候可以通过事件监听方式,通知各个实例触发该操作。
场景2:static 静态变量的更新
某些情况,会使用静态变量维护一些数据,当要对这些数据进行修改,仅仅触发某个后端实例的接口,是不够的,可以通过事件监听机制,其他实例也订阅该动作,同步更新相关变量。
Tips:还有很多场景,这边不赘述了,自行发散。
总结陈词
上文介绍了框架封装人员,如何处理事件监听逻辑,提供了一些思路分享。
事件监听更多情况下是订阅了事件,需要由外部主动发布事件,才能触发响应逻辑。其实还有数据监听、缓存监听等技术方案,即数据变化等情况下,会自动触发响应,比如:Redis-Key 的过期监听、OGG for Bigdata 的 Oracle 数据变化监听,关于这一点后面再开文章介绍。
本系列博文将介绍框架搭建人员如何以恰当的方式应对各式各样的情况,这也是此专栏的主题。
💗 后续将持续更新,请多多支持!
相关文章:
《框架封装 · Redis 事件监听》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...
小白学webgl合集-Three.js加载器
THREE.TextureLoader: 用途: 加载单个图像文件并将其作为纹理应用到材质上。示例: const loader new THREE.DataTextureLoader(); loader.load(path/to/data.bin, function (texture) {const material new THREE.MeshBasicMaterial({ map: texture });const geometry new TH…...
【算法】字符串的排列
难度:中等 给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。 换句话说,s1 的排列之一是 s2 的 子串 。 示例 1: 输入:…...
5-3.损失函数
文章最前: 我是Octopus,这个名字来源于我的中文名–章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的…...
SCSA第四天
ASPF FTP --- 文件传输协议 Tftp --- 简单文件传输协议 FTP协议相较于Tftp协议 ---- 1,需要进行认证 2,拥有一套完整的命令集 用户认证 防火墙管理员认证 ---- 校验登录者身份合法性 用户认证 --- 上网行为管理中的一环 上网用户认证 --- 三层认证…...
品牌策划必读:9本改变游戏规则的营销经典
作为深耕品牌十余年的策划人,这些年自学啃下的书不计其数。 这里特意挑选了几本知名度不高但是却非常有用的“遗珠”优质品牌策划书籍分享出来。 如果你是一位初步了解品牌的人,这些书籍既包含了品牌理论基础,也有实用的实践指导。 这些书…...
泛型
背景 优点 类型绝对安全避免强制类型转换 泛型类 定义 使用 举例 泛型类 // 泛型类 T就是类型参数 public class Generic<T>{// key这个成员变量的类型为T,T的类型由外部指定private T t;public void set(T t){this.t t;}public T get(){return t;} }使用 // 创建一个泛…...
react动态渲染列表与函数式组件
1.如何使用jsx语法动态渲染列表呢,下边我用一个例子来切实总结一下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scal…...
小程序内容管理系统设计
设计一个小程序内容管理系统(CMS)时,需要考虑以下几个关键方面来确保其功能完善、用户友好且高效: 1. 需求分析 目标用户:明确你的目标用户群体,比如企业、媒体、个人博主等,这将决定系统的功…...
HDFS 块重构和RedundancyMonitor详解
文章目录 1. 前言2 故障块的重构(Reconstruct)2.1 故障块的状态定义和各个状态的统计信息2.2 故障文件块的查找收集2.5.2.1 misReplica的检测2.5.2.2 延迟队列(postponedMisreplicatedBlocks)的构造和实现postponedMisreplicatedBlocks中Block的添加postponedMisreplicatedBloc…...
Power BI DAX常用函数使用场景和代码示例
Power BI函数表达式对于没有接触过的朋友可能会有些迷茫,花一点时间了解一下原理在学习一些常用的DAX函数,就可以解决工作中绝大部分问题,函数使用都是共同的。 以下是一些最常用的DAX函数,如聚合,计数,日期…...
机器学习与深度学习:区别与联系(含工作站硬件推荐)
一、机器学习与深度学习区别 机器学习(ML:Machine Learning)与深度学习(DL:Deep Learning)是人工智能(AI)领域内两个重要但不同的技术。它们在定义、数据依赖性以及硬件依赖性等方面…...
大模型/NLP/算法面试题总结5——Transformer和Rnn的区别
Transformer 和 RNN(循环神经网络)是两种常见的深度学习模型,广泛用于自然语言处理(NLP)任务。 它们在结构、训练方式以及处理数据的能力等方面有显著的区别。以下是它们的主要区别: 架构 RNN࿰…...
【RHCE】转发服务器实验
1.在本地主机上操作 2.在客户端操作设置主机的IP地址为dns 3.测试,客户机是否能ping通...
AI提示词:打造爆款标题生成器
打开GPT输入以下内容: # Role 爆款标题生成器## Profile - author: 姜小尘 - version: 02 - LLM: Kimi - language: 中文 - description: 利用心理学和市场趋势,生成吸引眼球的自媒体文章标题。## Background 一个吸引人的标题是提升文章点击率和传播力…...
skywalking-1-服务端安装
skywalking很优秀。 安装服务端 skywalking的服务端主要是aop服务,为了方便查看使用还需要安装ui。另外采集的数据我们肯定要存起来,这个数据库就直接用官方的banyandb。也就是aop、ui、banyandb都使用官方包。 我们的目的是快速使用和体验,…...
查看oracle ojdbc所支持的JDBC驱动版本
oracle jcbc驱动的下载地址参考:JDBC and UCP Downloads page 其实上文中对ojdbc所支持的JDBC驱动版本已经有说明了,不过,因为oracle的驱动包很多时间,都是在公司内部私服里上传维护的,上传的时候,可能又没…...
自媒体运营怎样引流客源?
不管是企业还是个人,越来越多都在做自媒体引流运营,那有什么引流客源的方式呢? 高质量内容:创作并分享有价值的内容,吸引目标受众,提升内容的分享和传播效果。 SEO优化:优化文章标题、关键词和…...
【算法】十进制转换为二进制
目的:将十进制转换为二进制 思路: 首先我们手算的情况是通过求余数算出进制数,同样代码也是通过做除法和求余数的方式,除法是得出下一次的被除数,而求余数是得到进制数 代码: #include<stdio.h>/…...
Postman中的API安全堡垒:全面安全性测试指南
🛡️ Postman中的API安全堡垒:全面安全性测试指南 在当今的数字化世界中,API安全性是保护数据和系统不可或缺的一环。Postman作为API开发和测试的领先工具,提供了多种功能来帮助开发者进行API安全性测试。本文将深入探讨如何在Po…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
