《框架封装 · 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…...
学圣学最终的目的是:达到思无邪的状态( 纯粹、思想纯正、积极向上 )
学圣学最终的目的是:达到思无邪的状态( 纯粹、思想纯正、积极向上 ) 中华民族,一直以来,教学都是以追随圣学为目标,所以中华文化也叫圣学文化,是最高深的上等学问; 圣人那颗心根本…...
JS进阶-构造函数
学习目标: 掌握构造函数 学习内容: 构造函数 构造函数: 封装是面向对象思想中比较重要的一部分,js面向对象可以通过构造函数实现的封装。 同样的将变量和函数组合到了一起并能通过this实现数据的共享,所不同的是借助…...
使用Spring Boot和Couchbase实现NoSQL数据库
使用Spring Boot和Couchbase实现NoSQL数据库 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 一、引言 NoSQL数据库越来越受到开发者的欢迎,特别是…...
【数据库】Redis主从复制、哨兵模式、集群
目录 一、Redis的主从复制 1.1 主从复制的架构 1.2 主从复制的作用 1.3 注意事项 1.4 主从复制用到的命令 1.5 主从复制流程 1.6 主从复制实现 1.7 结束主从复制 1.8 主从复制优化配置 二、哨兵模式 2.1 哨兵模式原理 2.2 哨兵的三个定时任务 2.3 哨兵的结构 2.4 哨…...
C基础day8
一、思维导图 二、课后习题 #include<myhead.h> #define Max_Stu 100 //函数声明 //学生信息录入函数 void Enter_stu(int *Num_Stu,char Stu_name[][50],int Stu_score[]); //查看学生信息 void Print_stu(int Num_Stu,char Stu_name[][50],int Stu_score[]); //求出成绩…...
【Spring成神之路】老兄,来一杯Spring AOP源码吗?
文章目录 一、引言二、Spring AOP的使用三、Spring AOP的组件3.1 Pointcut源码3.2 Advice源码3.3 Advisor源码3.4 Aspect源码 四、Spring AOP源码刨析4.1 configureAutoProxyCreator源码解析4.2 parsePointcut源码解析4.3 parseAdvisor源码解析4.4 parseAspect源码解析4.5 小总…...
轻松理解c++17的string_view
文章目录 轻松理解c17的string_view设计初衷常见用法构造 std::string_view常用操作作为函数参数 注意事项总结 轻松理解c17的string_view std::string_view 是 C17 引入的一个轻量级、不拥有(non-owning)的字符串视图类。它的设计初衷是提供一种高效、…...
【机器学习理论基础】回归模型定义和分类
定义 回归分析是研究自变量与因变量之间数量变化关系的一种分析方法,它主要是通过因变量 Y Y Y与影响它的自变量 X i X_i Xi 之间的回归模型,衡量自变量 X i X_i Xi 对因变量 Y Y Y 的影响能力的,进而可以用来预测因变量Y的发展趋势。…...
探讨4层代理和7层代理行为以及如何获取真实客户端IP
准备工作 实验环境 IP角色192.168.1.100客户端请求IP192.168.1.100python 启动的HTTP服务192.168.1.102nginx服务192.168.1.103haproxy 服务 HTTP服务 这是一个简单的HTTP服务,主要打印HTTP报文用于分析客户端IP #!/usr/bin/env python # coding: utf-8import …...
java算法day11
二叉树的递归遍历二叉树的非递归遍历写法层序遍历 递归怎么写? 按照三要素可以保证写出正确的递归算法: 1.确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且…...
wordpress伪静态化/网络营销的推广方式
Oracle 的 XML 实现?Oracle 已经通过的 XML DB 组件实现了 XML,该组件是企业版和标准版的标准特性。通过数据库配置助手 (DBCA) 或者运行一个目录脚本 catqm.sql,可以轻松安装 Oracle XML DB。XML DB 产品提供本文讨论的所有特性。要验证是否…...
赤峰做网站的网络公司/百度如何做广告
首先要说的是本文所说的缺陷并非指指针悬空或野指针造成的程序崩溃,我觉得那些问题只要小心的处理,是可以避免的。本文所说的缺陷是指指针对C对象封装的破坏。 想到写这个话题是因为看到有人问了一个问题“基类的私有成员会不会被子类继承?”…...
网站建设教程 三级分销/湘潭seo快速排名
2019独角兽企业重金招聘Python工程师标准>>> 这里是一个用Eclipse的JUnit4教程: 首先,在项目下建立一个test包,然后再就是新建测试类,右键,选择JUnit Test Case,如下图: 然后选择JUnit4&#…...
开州区城乡建设委员会官方网站/网络营销推广服务商
近日"超越时空的紫禁城"([url]www.beyondspaceandtime.org[/url])已正式上线运营,这是一个历经数年颇受业内人士关注的项目。能够再一次以虚拟现实的方式寻访故宫,于我个人而言,感慨颇多,顺手写下…...
php 快速网站开发/怎样推广自己的产品
curator delete indices --index .marvel- --older-than 3 --time-unit days --timestring %Y.%m.%d3 /data0/wwwroot/elasticsearch-1.4.1/data/elasticsearch/nodes/0/indices转载于:https://blog.51cto.com/201438gz/1754170...
济南网站排名推广/企业营销
前言: 在前两篇的文章中,我们学会了给组件添加属性、事件,以及对这些属性和事件进行描述添加,今天,我们就来小试一把这个组件吧,如果你忘记了前两篇文章的内容,可以从这里回顾一下: …...