springboot使用Redis发布订阅(Pub/Sub)实战

embedded/2025/1/23 6:38:01/

一、基本介绍

Redis 发布/订阅是一种消息传模式,其中发送者发送消息,而接收者(订阅者)接收消息。传递消息的通道称为channel。

例如下图的工流程,当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端。
在这里插入图片描述

二、对比

有人可能之前使用过RabbitMQ做消息队列,此时难免会产生疑惑,它与RabbitMQ有什么异同呢?它们的使用场景又都是什么呢?

Redis发布订阅(Pub/Sub)

  • Redis的发布订阅功能提供了一种一对多的消息通信模式,其中发布者发送消息,订阅者接收消息。
  • 它是轻量级的,主要适用于简单的消息广播场景。
  • 它的速度非常非常非常快,但是不能持久化。

它适用于实时性要求高、但对消息可靠性要求不高的场景,如实时通知、缓存更新、一、二级别缓存同步等。

RabbitMQ消息队列

  • RabbitMQ是一个实现了高级消息队列协议(AMQP)的消息队列服务,它支持多种消息传递模式,包括点对点、发布订阅和路由等。
  • 它是一个功能齐全的消息代理,提供了可靠的消息传递、消息持久化、消息确认和灵活的路由机制。

它适用于需要确保消息可靠送达、处理复杂业务逻辑和分布式系统的场景,速度上要慢于redis发布订阅,并且集成时比较重量级。

对比总结:如果需要可靠的消息传递和复杂的消息路由,RabbitMQ是更好的选择。如果只需要简单的消息广播,并且对性能有较高的要求,Redis的发布订阅可能就足够了。

三、实战

1、首先在你的springboot中引入redis,并能确保使用RedisTemplate这一步就不多做赘述了。
2、创建一个你要发送的消息实体,例如我创建了一个CaffeineCacheMessage消息类。注意因为需要网络流转,所以一定要实现序列化Serializable接口。

public class CaffeineCacheMessage implements Serializable {private String cacheName;private Object key;private Object value;private Integer type;public String getCacheName() {return cacheName;}public void setCacheName(String cacheName) {this.cacheName = cacheName;}public Object getKey() {return key;}public void setKey(Object key) {this.key = key;}public Object getValue() {return value;}public void setValue(Object value) {this.value = value;}public Integer getType() {return type;}public void setType(Integer type) {this.type = type;}

3、创建一个接收到消息的处理类RedisReceiver,用来走收到消息后的逻辑处理。

//收到消息进行逻辑处理
@Component
public class RedisReceiver{private static Logger log = LoggerFactory.getLogger(RedisReceiver.class);/**接收消息的方法*/public void receiveMessage(String message){log.info("接收到了消息:{}",message);// ...你自己的业务逻辑}}

4、关键点来了,创建一个自动配置类RdMessageListenerConfiguration,来设定和封装消息发送通道,消息接收类和接收方法。
注意我这里的MessageListenerAdapter listenerAdapter(RedisReceiver receiver)方法,它一定要与第三步的方法能对应上,不然监听器使用代理对象调用方法时就会找不到方法,报空指针异常。

/*** 用Redis的发布/订阅模式,来同步消息* @author: chenggh*/
@Configuration
public class RdMessageListenerConfiguration {@Value("${xxxx.topic.id}")String topicId;@AutowiredStringRedisTemplate redisTemplate;private static Logger log = LoggerFactory.getLogger(RdMessageListenerConfiguration.class);/*** redis消息监听器容器* 可以添加多个监听不同话题的redis监听器,只需要把消息监听器和相应的消息订阅处理器绑定,该消息监听器* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理* @param connectionFactory* @param listenerAdapter* @return*/@BeanRedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,MessageListenerAdapter listenerAdapter) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);//订阅了一个叫chat 的通道container.addMessageListener(listenerAdapter, new PatternTopic(topicId));//这个container 可以添加多个 messageListenerreturn container;}/*** 消息监听器适配器,绑定消息处理器,利用反射技术调用消息处理器的业务方法* @param receiver* @return*/@BeanMessageListenerAdapter listenerAdapter(RedisReceiver receiver) {//这个地方 是给messageListenerAdapter 传入一个消息接受的处理器,利用反射的方法调用“receiveMessage”//也有好几个重载方法,这边默认调用处理器的方法 叫handleMessage 可以自己到源码里面看return new MessageListenerAdapter(receiver, "receiveMessage");}public void publishUpdateMessage(Object key, Object value, String cacheName, Integer type) {CaffeineCacheMessage cacheMessage = new CaffeineCacheMessage();cacheMessage.setKey(key);cacheMessage.setValue(value);cacheMessage.setType(type);cacheMessage.setCacheName(cacheName);redisTemplate.convertAndSend(topicId, JSON.toJSONString(cacheMessage));}}

至此,redis的发布订阅实战就结束了。代码不是很多,但是设计和实现的很精巧,每一步的逻辑都清晰的写在了注释里,可以拿去即用。★,°:.☆( ̄▽ ̄)/$:.°★


http://www.ppmy.cn/embedded/156247.html

相关文章

博客之星2024年度总评选—我的技术总结之旅

在踏入2024年的尾声之际,回望过去一年的技术探索与实践,心中充满了感慨与收获。作为一名技术博主,我深知持续学习与分享的重要性,因此,本次我选择以“技术总结类”为主题,来盘点我在特定技术领域——人工智…

顺序表和链表(详解)

线性表 线性表( linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构,也就说是连续的一条直线。…

c++面试题,请使用STL的std::remove_if算法删除std::vector<int>容器中大于5的数字

请使用STL的std::remove_if算法删除std::vector容器中大于5的数字 在C 中, std::remove_if 算法并不会真正从容器中删除元素, 而是将满足条件的元素移动到容器末尾,并返回一个指向新的逻辑结束位置的迭代器。 你需要使用容器的 erase 成员函…

激光雷达和相机早期融合

通过外参和内参的标定将激光雷达的点云投影到图像上。 • 传感器标定 首先需要对激光雷达和相机(用于获取 2D 图像)进行外参和内参标定。这是为了确定激光雷达坐标系和相机坐标系之间的转换关系,包括旋转和平移。通常采用棋盘格等标定工具&…

[CTF/网络安全] 攻防世界 Web_php_unserialize 解题详析

代码审计 这段代码首先定义了一个名为 Demo 的类,包含了一个私有变量 $file 和三个魔术方法 __construct()、__destruct() 和 __wakeup()。其中: __construce()方法用于初始化 $file 变量__destruce方法用于输出文件内容__wakeup() 方法检查当前对象的…

SQLmap 注入 -04-cookies

1: firefox 先下载cookies 插件: 点击" 附加组件管理器", 然后进去输入cookies, 搜索, 下面这个安装的是 cookie Quick manager 下面看一下: 2下面进行测试: 注意: PHPSESSID 后面是 下面是例子: 上面运行的结果: 好&#xff…

【HF设计模式】06-命令模式

声明:仅为个人学习总结,还请批判性查看,如有不同观点,欢迎交流。 摘要 《Head First设计模式》第6章笔记:结合示例应用和代码,介绍命令模式,包括遇到的问题、采用的解决方案、遵循的 OO 原则、…

100条Linux命令汇总

本文章为个人成长笔记之一,感谢您的阅览。 内容简介 文件和目录操作命令(14 个)查看文件及内容处理命令(14 个)文件压缩及解压缩命令(4个)信息显示命令(11个)用户管理命令(10个)基础网络操作命令(12个)进程管理相关命令(15个)其他常用命令(10个) 文件和目录操作命令…