Redis实现发布/订阅功能(实战篇)

前言

博主在学习 Redis 实现发布订阅功能的时候,踩了太多的坑。

不是讲解不详细,看的一知半解;就是代码有问题,实际压根跑不起来!

于是博主萌生了自己写一个最新版且全程无错的博客供各位参考。希望各位不要把我才过的坑再踩一遍。(实战篇的所有代码均由本人测试,全程无Bug。)

废话不多说,让我们进入实战篇的学习!

在开始实战篇的之前,我们先一起回顾下原理篇的内容。

Redis 发布/订阅的优点

  • 高性能:Redis 作为内存存储,具备极高的读写性能,能够快速处理发布和订阅消息。
  • 简单易用:Redis 的发布/订阅接口简单,易于集成和使用。
  • 实时性强:发布的消息会立即传递给所有订阅者,具备高实时性。

Redis 发布/订阅的缺点

  • 消息丢失:由于 Redis 是内存存储,如果 Redis 实例宕机,未处理的消息可能会丢失。
  • 无法持久化:Redis 的发布/订阅模式不支持消息持久化,无法存储和检索历史消息。
  • 订阅者不可控:发布者无法控制订阅者的数量和状态,无法保证所有订阅者都能接收到消息。
  • 无确认机制:发布者无法确认消息是否被订阅者接收和处理。

正如上述中Redis的缺点,Redis的发布订阅功能并不可靠,如果我们需要保证消息的可靠性、包括确认、重试等要求,我们还是要选择使用MQ实现发布订阅。

Redis的发布/订阅应用场景:

  • 对于消息处理可靠性要求不强
  • 消息无需持久化
  • 消费能力无需通过增加消费方进行增强
  • 架构简单 中小型系统不希望应用过多中间件

Redis发布订阅命令

命令

描述

Redis Unsubscribe 命令

指退订给定的频道

Redis Subscribe 命令

订阅给定的一个或多个频道的信息

Redis Pubsub 命令

查看订阅与发布系统状态

Redis Punsubscribe 命令

退订所有给定模式的频道

Redis Publish 命令

将信息发送到指定的频道

Redis Psubscribe 命令

订阅一个或多个符合给定模式的频道


正式开始

一、添加依赖

首先,确保你已经安装并配置好 Redis 服务器,并创建了 Spring Boot 项目,在pom.xml中引入依赖。

<!-- 所需依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

二、配置文件中配置Redis

spring:# 项目名称application:name: test-redis-boot# Redis 配置data:redis:host: 填写自己的主机IPport: 8000password: 有则填,没有去掉这个属性database: 1# 连接超时时间timeout: 10slettuce:pool:# 连接池中的最小空闲连接min-idle: 5# 连接池中的最大空闲连接max-idle: 8# 连接池的最大数据库连接数max-active: 20# #连接池最大阻塞等待时间(使用负值表示没有限制)max-wait: -1ms

三、创建Redis配置类

创建一个配置类,用于配置 Redis连接工厂和消息监听器监听通道信息

注:此配置类无需死记硬背。只需大致了解每个方法的作用即可。

/*** @Description Redis 配置类,用于配置 Redis 连接工厂和消息监听器监听通道信息* @Author gongming.Zhang* @Date 2024/9/11 18:27* @Version 1.0*/
@Configuration
@Slf4j
public class RedisConfig {/*** 自定义 RedisTemplate 序列化方式** @param redisConnectionFactory Redis 连接的线程安全工厂* @return 模板类*/@Beanpublic RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();// 绑定 RedisConnectionFactoryredisTemplate.setConnectionFactory(redisConnectionFactory);// 创建 Jackson2JsonRedisSerializer 序列方式,对象类型使用 Object 类型。ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.activateDefaultTyping(new LaissezFaireSubTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(objectMapper, Object.class);// 设置 RedisTemplate 序列化规则,因为 key 通常是普通的字符串,所以使用StringRedisSerializer即可,而 value 是对象时,才需要使用序列化与反序列化。redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash key 序列化规则redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// 属性设置后操作redisTemplate.afterPropertiesSet();log.info("RedisTemplate 自定义序列化配置完毕...");return redisTemplate;}/*** 配置主题订阅* * 可以添加多个监听器,监听多个通道,只需要将消息监听器与订阅的通道/主题绑定即可。* addMessageListener(MessageListener listener, Collection<? extends Topic> topics):将消息监听器与多个订阅的通道/主题绑定* addMessageListener(MessageListener listener, Topic topic):将消息监听器与订阅的通道/主题绑定** @param connectionFactory Redis 连接的线程安全工厂* @return 容器对象*/@Beanpublic RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,MessageListenerAdapter listenerAdapter) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();// 设置连接工厂,RedisConnectionFactory 可以直接从容器中取,也可以从 RedisTemplate 中取container.setConnectionFactory(connectionFactory);// 订阅名称叫 cache 的通道, 类似 Redis 中的 subscribe 命令container.addMessageListener(listenerAdapter, new ChannelTopic("cache"));// 订阅名称以 'test-' 开头的全部通道, 类似 Redis 的 pSubscribe 命令container.addMessageListener(listenerAdapter, new PatternTopic("test-*"));log.info("消息监听器和通道绑定完毕...");return container;}/*** 配置消息监听适配器** @param redisReceiveListener* @return*/@Beanpublic MessageListenerAdapter listenerAdapter(RedisReceiveListener redisReceiveListener) {return new MessageListenerAdapter(redisReceiveListener);}
}

四、创建消息发送服务端

创建一个消息发布类,用于向客户端发布消息。

/*** @Description 消息发布服务端* @Author gongming.Zhang* @Date 2024/9/12 9:42* @Version 1.0*/
@Component
@Slf4j
public class MessagePublisher {@Autowiredprivate RedisTemplate<Object, Object> redisTemplate;/*** 服务端发布消息** @param channel 通道名* @param message 待发送的消息*/public void sendMessage(String channel, String message) {redisTemplate.convertAndSend(channel, message);log.info("消息发送成功...  channel={}, message={}", channel, message);}}

五、创建监听器(客户端)

用于监听服务端发送的消息,每次服务端发送新消息时,都会自动调用onMessage()方法。

/*** @Description Redis 消息监听器* @Author gongming.Zhang* @Date 2024/9/11 18:53* @Version 1.0*/
/*当收到订阅的消息时,会将消息交给这个类处理。* 可以直接实现 MessageListener 接口,也可以继承它的实现类 MessageListenerAdapter.* 自动多线程处理,打印日志即可看出,即使手动延迟,也不会影响后面消息的接收。*/
@Component
@Slf4j
public class RedisReceiveListener implements MessageListener {@Autowiredprivate RedisTemplate<Object, Object> redisTemplate;/*** 处理回调逻辑。每次新消息到达时,都会调用此方法。通过 onMessage 方法执行业务代码* <p>* 该接口不仅可以访问实际消息,还可以访问接收消息的频道(Channel),以及订阅时用于匹配频道(Channel)的模式。* 此信息使被调用者不仅可以通过内容区分各种消息,还可以检查其他详细信息。** @param message 消息对象,不能为 null* @param pattern 与通道匹配的模式(如果指定),可以为 null*/@Overridepublic void onMessage(Message message, byte[] pattern) {// 1.获取消息所属的通道  -->  首先获取 字符串序列化器,再从给定的二进制数据中反序列化对象。String channel = redisTemplate.getStringSerializer().deserialize(message.getChannel());// 2.获取客户端发送的消息内容  -->  后期可以根据自己项目中 消息 的类型,来确定用什么序列化器Object msg = redisTemplate.getValueSerializer().deserialize(message.getBody());log.info("收到Redis订阅消息: channel={} msg={}", channel, msg);}
}

六、编写Controller测试

/*** @Description 测试订阅发布功能* @Author gongming.Zhang* @Date 2024/9/12 10:13* @Version 1.0*/
@RestController
@RequestMapping(value = "/api/v1/publish")
public class PublisherController {@Autowiredprivate MessagePublisher publisher;@GetMapping("/sendMessage")public String sendMessage(@RequestParam(value = "message") String message, @RequestParam(value = "channel") String channel) {publisher.sendMessage(channel, message);return "Message published: " + message;}
}

七、测试响应数据

至此,我们 SpringBoot 整合 Redis 实现发布订阅功能已经完成!


总结

通过本文,我们详细介绍了如何在 SpringBoot 中整合 Redis 实现发布/订阅功能,并提供了详细的代码示例。Redis 发布/订阅模式以其高性能和简单易用的特点,在实时消息传递场景中有着广泛的应用,但同时也需要注意其消息丢失和无法持久化等缺点,需要根据实际业务需求选择。

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

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

相关文章

【Python篇】深度探索NumPy(下篇):从科学计算到机器学习的高效实战技巧

文章目录 Python NumPy学习指南前言第六部分&#xff1a;NumPy在科学计算中的应用1. 数值积分使用梯形规则进行数值积分使用Simpson规则进行数值积分 2. 求解微分方程通过Euler方法求解一阶常微分方程使用scipy.integrate.solve_ivp求解常微分方程 3. 随机过程模拟模拟布朗运动…

Llama 3.1 Omni:颠覆性的文本与语音双输出模型

你可能听说过不少关于语言模型的进展,但如果告诉你,有一种模型不仅能生成文本,还能同时生成语音,你会不会觉得特别酷?今天咱们就来聊聊一个相当前沿的项目——Llama 3.1 Omni模型。这个模型打破了传统的文字生成边界,直接让文本和语音同时输出,实现了真正的"多模态…

网络爬虫到底难在哪里?

如果你是自己做爬虫脚本开发&#xff0c;那确实难&#xff0c;因为你需要掌握Python、HTML、JS、xpath、database等技术&#xff0c;而且还要处理反爬、动态网页、逆向等情况&#xff0c;不然压根不知道怎么去写代码&#xff0c;这些技术和经验储备起码得要个三五年。 比如这几…

基于milvus数据库的RAG-Demo

1.上传文本并将文本向量化 import os from django.conf import settings from langchain.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter, CharacterTextSplitter from langchain.vectorstores import Chroma from l…

C++掉血迷宫

目录 开头程序程序的流程图程序游玩的效果下一篇博客要说的东西 开头 大家好&#xff0c;我叫这是我58。 程序 #include <iostream> #include <string> #include <cstring> using namespace std; enum RBYG {R 1,B 2,Y 4,G 7, }; struct heal {int ix…

Linux服务器本地部署Joplin Server并实现手机电脑多端同步文档

文章目录 前言1. 安装Docker2. 自建Joplin服务器3. 搭建Joplin Sever4. 安装cpolar内网穿透5. 创建远程连接的固定公网地址 前言 本文主要介绍如何在自己的服务器上利用docker搭建 Joplin Server&#xff0c;并对同步进行配置&#xff0c;再结合cpolar内网穿透工具实现公网远程…

学习Stable Diffusion使用 Roop插件轻松换脸(附插件)

在今天的分享中&#xff0c;将了解到如何获取并应用StableDiffusion的Roop插件&#xff0c;以达到完美的面部替换效果。 Roop是一款强大的工具&#xff0c;使您能够轻松地交换面孔并达到逼真的效果。 无论是艺术家、内容创作者&#xff0c;还是仅仅想要尝试图像处理的乐趣&am…

关于Vue2里 v-for和v-if一起用的时候会出现的问题

关于Vue2里 v-for和v-if一起用的时候会出现的问题 &#x1f389;&#x1f389;&#x1f389;欢迎来到我的博客,我是一名自学了2年半前端的大一学生,熟悉的技术是JavaScript与Vue.目前正在往全栈方向前进, 如果我的博客给您带来了帮助欢迎您关注我,我将会持续不断的更新文章!!!&…

使用cmd命令窗口操作mongodb

一、效果显示 二、下载MongoDB 1. 在官网下载安装MongoDB 官网网址&#xff1a;Download MongoDB Community Server | MongoDB 我安装的版本是7.0.14(注意安装到空闲磁盘) 三、启动MongoDB服务 1. 配置环境变量 注意替换为你的路径。 2. 在MongoDB的data下创建db文件夹 在…

51单片机应用开发---二进制、十六进制与单片机寄存器之间的关系(跑马灯、流水灯实例)

实现目标 1、掌握二进制与十六进制之间的转换 2、掌握单片机寄存器与二进制、十六进制之间的转换 3、掌握单片机驱动跑马灯、流水灯的原理 一、二进制与十六进制之间的转换 1、二进制 二进制&#xff08;binary&#xff09;&#xff0c; 是在数学和数字电路中以2为基数的…

计算机毕业设计 乡村生活垃圾管理系统的设计与实现 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Java接口与继承:构建灵活系统的基石

在Java编程语言中&#xff0c;接口&#xff08;Interface&#xff09;是一种定义方法规范的类型&#xff0c;它是一种特殊的抽象类&#xff0c;可以被类实现&#xff08;Implement&#xff09;或被其他接口继承&#xff08;Extend&#xff09;。接口是Java实现多态和模块化设计…

无人机之控制距离篇

无人机的控制距离是一个复杂且多变的概念&#xff0c;它受到多种因素的共同影响。以下是对无人机控制距离及其影响因素的详细分析&#xff1a; 一、无人机控制距离的定义 无人机控制距离指的是遥控器和接收机之间的最远传输距离。这个距离决定了无人机在操作者控制下能够飞行的…

前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)

图形验证码是网站安全防护的重要组成部分&#xff0c;能有效防止自动化脚本进行恶意操作&#xff0c;如何实现一个简单的运算图形验证码&#xff1f;本文封装了一个简单的js类&#xff0c;可以用于生成简单但安全的图形验证码。它支持自定义验证码样式&#xff0c;包括字体大小…

HarmonyOS使用LocationButton获取地理位置

LocationButton LocationKit getAddressesFromLocation方法 步骤&#xff1a; 整合 LocationButton并获取经纬度通过 LocationKit 将经纬度转为地址信息将地址信息渲染到页面上处理异常情况&#xff08;闪退&#xff09; LocationButton({ icon: LocationIconStyle.LINE…

828华为云征文|Flexus云服务器X实例部署宝塔运维面板

本次华为云Flexus云服务器X实例部署宝塔运维面板教学&#xff0c;这次是推陈出新啊 之前的云耀云服务器L实例已经很不错了&#xff0c;大力赞叹华为云的 同时感谢华为云提供优惠卷&#xff0c;只能说白嫖真是太棒了 华为云近期正在筹办华为云828企业节活动&#xff0c;90款免…

Parallels Desktop 20破解版(Mac虚拟机) v20.0.0 for Mac 最新商业版(支持M系列)

Parallels Desktop 20是一款目前功能最强大灵活度最高的虚拟机软件&#xff0c;可运行数千种 Windows 应用程序&#xff0c;如 Microsoft Office、Internet Explorer、Access、Quicken、QuickBooks、Visual Studio&#xff0c;甚至支持对图像要求较高的游戏和 CAD 项目&#xf…

渗透测试综合靶场 DC-2 通关详解

一、准备阶段 准备工具如Kali Linux&#xff0c;下载并设置DC-2靶场机。确保攻击机和靶机在同一网络段&#xff0c;通常设置为桥接模式或NAT模式。 1.1 靶机描述 Much like DC-1, DC-2 is another purposely built vulnerable lab for the purpose of gaining experience in …

python毕业设计作品:python手机数码商城系统毕业设计源代码作品和开题报告(Django框架)

博主介绍&#xff1a;黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者&#xff0c;CSDN博客专家&#xff0c;在线教育专家&#xff0c;CSDN钻石讲师&#xff1b;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程&#xff…

算法知识点———并查集

并查集是一种用于管理元素所属集合的数据结构&#xff0c;实现为一个森林&#xff0c;其中每棵树表示一个集合&#xff0c;树中的节点表示对应集合中的元素。并查集支持两种操作&#xff1a; 合并&#xff08;Union&#xff09;&#xff1a;合并两个元素所属集合&#xff08;合…