SpringBoot 整合 Redis 实现消息发布订阅实战
【摘要】 在后端开发中,很多场景需要实现模块解耦、异步通知,比如订单状态变更通知、系统配置刷新、日志告警推送等。Redis 自带的 Pub/Sub 发布订阅模式轻量易用,不需要额外部署消息中间件,非常适合简单的消息通知场景。本文基于 SpringBoot 整合 RedisTemplate,手把手实现消息发布、消息监听订阅,附带完整可运行代码
前言
消息队列是后端解耦的常用方案,但很多小型项目、内部管理系统,只是需要简单的事件通知,如果单独部署 RabbitMQ 会增加运维成本。Redis 原生支持 Pub/Sub 发布订阅模型,它是一种广播模式:发布者向指定频道发送消息,所有订阅该频道的消费者都能收到消息。
⚠️ 注意:Redis Pub/Sub 不是持久化消息队列。消息发送时,如果消费者离线,这条消息直接丢失,不会缓存。所以它适合通知类场景,不适合订单支付、库存扣减这类不能丢消息的业务。
一、环境依赖
SpringBoot 版本 2.7.x,引入 spring-boot-starter-data-redis:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
application.yml 配置 Redis 连接:
spring:
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
二、配置消息监听容器
想要订阅 Redis 频道消息,需要配置 MessageListenerContainer,绑定消息监听处理器。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
@Configuration
public class RedisPubSubConfig {
// 定义监听的频道
public static final String TOPIC_SYSTEM_NOTIFY = "system:notify";
// 消息监听适配器,绑定处理类
@Bean
public MessageListenerAdapter listenerAdapter(RedisMessageReceiver receiver) {
// 指定接收消息后执行的方法名
return new MessageListenerAdapter(receiver, "receiveMessage");
}
// 监听容器
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory factory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory);
// 订阅指定频道
container.addMessageListener(listenerAdapter, new ChannelTopic(TOPIC_SYSTEM_NOTIFY));
return container;
}
}
三、消息接收处理器
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class RedisMessageReceiver {
/**
* 消息接收方法
* @param message 收到的消息字符串
*/
public void receiveMessage(String message) {
log.info("【Redis订阅收到消息】:{}", message);
// 这里写业务逻辑:刷新配置、推送站内通知、打印告警等
}
}
四、消息发布工具类/测试接口
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/redis/pub")
public class RedisPubController {
@Resource
private RedisTemplate<String, Object> redisTemplate;
@GetMapping("/send")
public String sendMsg(@RequestParam String content) {
redisTemplate.convertAndSend(RedisPubSubConfig.TOPIC_SYSTEM_NOTIFY, content);
return "消息发布成功:" + content;
}
}
五、测试流程
- 启动 SpringBoot 项目,容器会自动订阅
system:notify频道 - 浏览器访问接口:
[http://127.0.0.1:8080/redis/pub/send?content=](http://127.0.0.1:8080/redis/pub/send?content=)系统配置已更新 - 查看控制台日志,可以看到
【Redis订阅收到消息】:系统配置已更新
六、核心特性与坑点总结
- 广播机制:同一个频道多个订阅者,消息会发给所有订阅者;不是点对点消费,没有 ack 确认。
- 消息不持久化:消费者离线期间发布的消息直接丢失,重启后收不到历史消息。
- 不支持消息堆积:Redis Pub/Sub 没有队列,消息发送瞬间分发完毕,无法回溯。
- 序列化问题:如果 RedisTemplate 使用 JdkSerializationRedisSerializer,消息会带序列化前缀,监听端拿到的是二进制。推荐使用 StringRedisTemplate 处理纯文本消息。
- 频道和模式订阅:除了固定 ChannelTopic,还支持 PatternTopic 通配符订阅,例如
system:*匹配所有 system 开头频道。
七、选型对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Redis Pub/Sub | 零额外部署、代码简单、低延迟 | 消息丢失、无堆积、无重试 | 配置刷新、实时通知、日志广播 |
| RabbitMQ | 消息持久化、ACK、重试、死信队列 | 需要独立部署、运维复杂 | 订单、支付、库存等可靠业务 |
八、生产环境优化建议
- 消息体尽量简短复杂对象建议序列化为 JSON 字符串传输;
- 消息消费逻辑做好 try-catch,避免单个消息异常导致监听线程卡死;
- 重要业务不要依赖 Redis Pub/Sub,优先专业 MQ;
- 监听容器可以配置线程池,提高消息并发消费能力。
结语
Redis Pub/Sub 是一个轻量化的事件通知方案,门槛很低,适合快速实现系统内异步解耦。很多新手容易把它当成可靠消息队列使用,最后出现消息丢失问题。理解它的底层限制,在合适场景下使用,才能发挥它的价值。本篇代码可以直接复制到项目中运行,快速验证发布订阅能力。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)