重学SpringBoot3-集成Redis(六)之消息队列

news2024/11/23 6:16:29

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》
期待您的点赞👍收藏⭐评论✍

重学SpringBoot3-集成Redis(六)之消息队列

  • 1. 什么是发布/订阅(Pub/Sub)?
  • 2. 场景应用
  • 3. Spring Boot 3 整合 Redis 实现发布/订阅
    • 3.1. 添加依赖
    • 3.2. 配置 Redis 连接
    • 3.3. 实现消息发布功能
    • 3.4. 实现消息订阅功能
    • 3.5. 测试发布/订阅功能
    • 3.6. 使用Redisson
  • 4. 总结

Redis 不仅是一个高效的缓存解决方案,也具备强大的消息队列功能。通过 Redis 的 发布/订阅(Pub/Sub) 机制,开发者可以轻松实现服务之间的通信和消息传递功能,而无需引入专门的消息队列工具。这篇文章将介绍如何通过 Spring Boot 3Redis 实现消息队列的发布与订阅功能。

1. 什么是发布/订阅(Pub/Sub)?

发布/订阅是一种消息传递模式,发布者发送消息到某个频道(channel),而订阅了该频道的所有订阅者都会收到该消息。这种模式与传统的消息队列不同,不会将消息存储下来,而是将其立即广播给所有的订阅者。因此,发布/订阅模式非常适合用于通知、事件广播等实时性较强的场景。

  • 发布者:向一个或多个频道发布消息。
  • 订阅者:订阅一个或多个频道,实时接收消息。
图片来源:https://pdai.tech/md/db/nosql-redis/db-redis-x-pub-sub.html

2. 场景应用

  • 事件驱动系统:如任务通知、状态更新、日志广播。
  • 消息通知服务:如实时的新闻推送、股票行情推送。
  • 微服务通信:不同服务之间的消息传递。

3. Spring Boot 3 整合 Redis 实现发布/订阅

在 Spring Boot 3 中,我们可以通过 Spring Data Redis 轻松集成 Redis 的发布/订阅功能。

3.1. 添加依赖

首先,我们需要在项目的 pom.xml 文件中添加必要的依赖,详细参考重学SpringBoot3-集成Redis(一)基本使用。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

3.2. 配置 Redis 连接

application.yml 中配置 Redis 连接信息:

spring:
  data:
    redis:
      host: localhost
      port: 6379            # Redis 端口
      password:             # 如果有密码可以在这里配置
      lettuce:
        pool:
          max-active: 100    # 最大并发连接数
          max-idle: 50       # 最大空闲连接数
          min-idle: 10       # 最小空闲连接数

3.3. 实现消息发布功能

首先,我们需要创建一个 消息发布者,用于发送消息到特定的频道:

package com.coderjia.boot310redis.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * @author CoderJia
 * @create 2024/10/6 下午 10:44
 * @Description
 **/
@Component
public class MessagePublisher {

    @Autowired
    private RedisTemplate redisTemplate;

    public void publish(String channel, String message) {
        redisTemplate.convertAndSend(channel, message);
        System.out.println("Message published to channel " + channel + ": " + message);
    }
}

在这个类中,RedisTemplate 被用来将消息发送到指定的频道。

3.4. 实现消息订阅功能

接下来,我们实现一个 消息订阅者,用于监听特定频道的消息:

package com.coderjia.boot310redis.config;

import org.springframework.stereotype.Component;

/**
 * @author CoderJia
 * @create 2024/10/6 下午 10:45
 * @Description
 **/
@Component
public class MessageSubscriber {

    public void onMessage(String message, String channel) {
        System.out.println("Received message from channel " + channel + ": " + message);
    }
}

为了让这个订阅者生效,我们需要注册一个消息监听器:

package com.coderjia.boot310redis.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @author CoderJia
 * @create 2024/10/4 下午 12:43
 * @Description
 **/
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        // 使用String序列化器序列化Key
        template.setKeySerializer(new StringRedisSerializer());

        // 使用Jackson2JsonRedisSerializer序列化Value
        ObjectMapper objectMapper = new ObjectMapper();
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(objectMapper,Object.class);
        template.setValueSerializer(serializer);

        return template;
    }


    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                                   MessageListenerAdapter listenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(listenerAdapter, new ChannelTopic("myChannel"));
        return container;
    }

    @Bean
    public MessageListenerAdapter listenerAdapter(MessageSubscriber subscriber) {
        return new MessageListenerAdapter(subscriber, "onMessage");
    }
}

在这个配置类中,我们使用 RedisMessageListenerContainer 来监听频道消息,并使用 MessageListenerAdapter 将消息处理委托给 MessageSubscriber

3.5. 测试发布/订阅功能

在我们的控制器或服务中,我们可以调用 MessagePublisher 来发布消息,并观察 MessageSubscriber 是否正确接收消息。

package com.coderjia.boot310redis.demos.web;

import com.coderjia.boot310redis.config.MessagePublisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author CoderJia
 * @create 2024/10/6 下午 10:47
 * @Description
 **/
@RestController
public class PubSubController {

    @Autowired
    private MessagePublisher messagePublisher;

    @GetMapping("/publish")
    public String publishMessage(@RequestParam String message) {
        messagePublisher.publish("myChannel", message);
        return "Message published!";
    }
}

现在,我们可以启动应用程序,并通过访问 curl http://localhost:8080/publish?message=Hello 来测试消息发布,订阅者会自动接收到该消息。

测试

也可以使用 redis 命令 PUBLISH myChannel "Hello, world!" 向渠道发布消息,订阅者同样可以接收到消息。

PUBLISH发布消息

3.6. 使用Redisson

使用 Redisson 同样能能实现发布订阅功能,而且是更接近 MQ 使用方式,下列代码仅供参考。

    public void publish(String channel, String message) {
        // redisTemplate.convertAndSend(channel, message);
        // System.out.println("Message published to channel " + channel + ": " + message);

        // 获取Topic
        RTopic topic = redissonClient.getTopic("myChannel");

        // 向渠道发送消息
        topic.publish("Hello, world!");

        topic.addListener(String.class, (channel1, message1) -> {
            System.out.println("Received message from channel " + channel1 + ": " + message1);
        });
    }

4. 总结

通过 Spring Boot 3 与 Redis 的整合,消息发布与订阅功能的实现非常简洁且高效。Redis 的发布/订阅功能不仅可以用于简单的消息通知,还可以结合其他业务场景,如微服务通信、日志广播等。虽然 Redis 的 Pub/Sub 并不具备消息持久化的能力,但它在需要即时消息传递的场景下,具有很高的性能和灵活性。

这篇文章为 Redis 消息队列功能奠定了基础,后续将深入 Redis 的其他功能,如缓存管理、分布式锁等。如果你对 Redis 有其他问题或建议,欢迎留言讨论!

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

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

相关文章

EtherNet/IP 转 EtherNet/IP, EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关

EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关https://item.taobao.com/item.htm?ftt&id822721028899 协议转换通信网关 EtherNet/IP 转 EtherNet/IP GW系列型号 MS-GW22 概述 简介 MS-GW22 是 EtherNet/IP 和 EtherNet/IP 协议转换网关&#xff0c;…

4.扩散模型的似然函数最大化(1)

1.似然函数最大化 扩散模型的训练目标是负的对数似然的一个变分下界(VLB)。在本节中&#xff0c;我们总结并调查最近关于扩散模型的似然最大化的工作。首先我们介绍似然函数最大化的意义&#xff0c;然后重点讨论3种类型的方法:噪声调度优化、逆向方差学习和精确的对数似然估计…

20年408数据结构

第一题&#xff1a; 解析&#xff1a;这种题可以先画个草图分析一下&#xff0c;一下就看出来了。 这里的m(7,2)对应的是这图里的m(2,7),第一列存1个元素&#xff0c;第二列存2个元素&#xff0c;第三列存3个元素&#xff0c;第四列存4个元素&#xff0c;第五列存5个元素&#…

胤娲科技:00后揭秘——AI大模型的可靠性迷局

当智能不再“靠谱”&#xff0c;我们该何去何从&#xff1f; 想象一下&#xff0c;你向最新的GPT模型提问&#xff1a;“9.9和9.11哪个大&#xff1f;”这本应是个小菜一碟的问题&#xff0c;却足以让不少高科技的“大脑”陷入沉思&#xff0c; 甚至给出令人啼笑皆非的答案。近…

卡码网104.建造最大岛屿

题目 104. 建造最大岛屿 (kamacoder.com) 代码&#xff08;ACM 首刷看解析&#xff09;&#xff1a; #include<iostream> #include<vector> #include<unordered_map> #include<unordered_set> using namespace std;int dir[4][2] {1,0,-1,0,0,1,0,-…

C++ 算法学习——1.8 悬线法

1.问题引入&#xff1a;对于一个矩形图&#xff0c;图中放置着不少障碍&#xff0c;要求出最大的不含障碍的矩形。 2.分析&#xff1a;显然一个极大矩形是左右上下都被障碍挡住&#xff0c;无法再扩大的矩形&#xff0c;此时障碍也包括边界。 3.方法&#xff1a;悬线法考虑以…

计算机组成原理实验三 数据寄存器组R0..R3, MAR, ST, OUT

实验目的和要求 目的&#xff1a;了解模型机中各种寄存器结构、工作原理及其控制方法。 要求&#xff1a;利用CP226 实验系统上的K16..K23 开关做为DBUS 的数据&#xff0c;其它开关做为控制信号&#xff0c;将数据写入寄存器&#xff0c;数据寄存器组R0..R3&#xff0c;地址…

【大数据】Flink CDC 实时同步mysql数据

目录 一、前言 二、Flink CDC介绍 2.1 什么是Flink CDC 2.2 Flink CDC 特点 2.3 Flink CDC 核心工作原理 2.4 Flink CDC 使用场景 三、常用的数据同步方案对比 3.1 数据同步概述 3.1.1 数据同步来源 3.2 常用的数据同步方案汇总 3.3 为什么推荐Flink CDC 3.4 Flink …

进程间通信(匿名管道 创建管道及分配任务代码)

文章目录 一.进程间通信进程为什么要通信&#xff1f;进程如何通信 二.管道匿名管道pipe写端慢写入&#xff0c;读端等待写端写入&#xff0c;读端不读 && 管道的大小写端关闭&#xff0c;读端不会读取写端写入&#xff0c;读端关闭字节流 总结安全问题 三.进程池创建管…

VADv2 论文学习

VADv2: End-to-End Vectorized Autonomous Driving via Probabilistic Planning 解决了什么问题&#xff1f;相关工作感知运动预测规划自动驾驶领域的大语言模型 提出了什么方法&#xff1f;场景编码器概率规划训练分布损失冲突损失场景 Token 损失 推理 实验实验设定指标消融实…

AI类课程的笔记

信息论、导论、模式识别&#xff08;数据挖掘&#xff09;、语义网络与知识图谱、深度学习、强化学习 &#xff08;零&#xff09;信息论 详见另一篇博文 信息论自总结笔记(仍然在更新)_信息论也更新了-CSDN博客https://blog.csdn.net/sinat_27382047/article/details/12690…

【Unity踩坑】Unity导出的UWP项目编译失败

在Unity中导出了UWP平台的项目后&#xff08;Xaml或D3D&#xff09;&#xff0c;使用Visual Studio编译时发生错误&#xff1a; Error: Unity.IL2CPP.Building.BuilderFailedException: Lump_libil2cpp_vm.cpp 查找后发现是Visual Studio 与Unity兼容的问题 原贴&#xff1a;…

数据分析案例-机器学习工程师薪资数据可视化分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

bus中设备驱动的probe触发逻辑和device、driver的添加逻辑

注&#xff1a;以下的代码皆摘自于linux 4.9.88版本的内核源码&#xff0c;不同版本可能有所出入。 往期内容&#xff1a; 驱动中的device和device_driver结构体bus总线的相关结构体和注册逻辑 1. driver的probe触发方式 在 Linux 设备模型中&#xff0c;probe() 函数是驱动…

自动驾驶系列—智能驾驶中的“换挡革命”:线控换挡技术详解

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

Java垃圾回收简述

什么是Java的垃圾回收&#xff1f; 自动管理内存的机制&#xff0c;负责自动释放不再被程序引用的对象所占用的内存。 怎么触发垃圾回收&#xff1f; 内存不足时&#xff1a;JVM检测到堆内存不足时&#xff0c;无法为新的对象分配内存时&#xff0c;会自动触发垃圾回收。手动…

UDP协议【网络】

文章目录 UDP协议格式 UDP协议格式 16位源端口号&#xff1a;表示数据从哪里来。16位目的端口号&#xff1a;表示数据要到哪里去。16位UDP长度&#xff1a;表示整个数据报&#xff08;UDP首部UDP数据&#xff09;的长度。16位UDP检验和&#xff1a;如果UDP报文的检验和出错&…

【电路】1.2 电流和电压的参考方向

1.2 电流和电压的参考方向 参考方向就是一个假设的方向&#xff08;类似中学物理的正方形&#xff09;&#xff0c;选参考方向的原因是电路结构略显复杂&#xff0c; 无法直接看出支路电压、电流的实际方向&#xff0c;参考方向可以任意选择&#xff0c;任意支路电压、电流只有…

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【272-284】

272. 包基本介绍 272.1 看一个应用场景 272.2 包的三大作用 272.3 包的基本语法 273. 包原理 274. 包快速入门 在不同的包下面创建不同的Dog类 275. 包命名 276. 常用的包 一个包下,包含很多的类,java 中常用的包有: java.lang.* //lang 包是基本包&#xff0c;默认引入&…

【英语】5. 考研英语语法体系

文章目录 前言句字的成分一、常规句型简单句&#xff08;5 种&#xff09;1. 定义&#xff1a;句子中只包含 *一套主谓结构* 的句子。&#xff08;一个句子只能有一个谓语动词&#xff09;2. 分类 并列句&#xff08;由关联词组成&#xff09;&#xff08;3 种&#xff09;基本…