RedisTemplate的publish方法发不出消息,大概率因未配对监听器或序列化不一致:默认JdkSerializationRedisSerializer导致订阅端解析失败,需改用StringRedisTemplate或指定StringRedisSerializer;且必须显式配置RedisMessageListenerContainer并注册监听器,Spring Boot 2.6+已禁用自动配置。

RedisTemplate的publish方法为什么发不出消息?
直接调用 redisTemplate.publish() 没反应,大概率是没配对监听器或序列化不一致。Spring Boot 的 RedisTemplate 默认使用 JdkSerializationRedisSerializer,而 Redis 订阅通道本身不走序列化——它只认原始 byte[] 或字符串。一旦你用默认 template 发送,实际发出去的是带 JDK 序列化头的二进制流,订阅端收到后解析失败,静默丢弃。
解决办法是:为发布/订阅单独配一个不序列化的 StringRedisTemplate,或者手动指定 StringRedisSerializer 给 RedisTemplate 的 key/value serializer。
- 推荐用
StringRedisTemplate:它默认就是字符串序列化,开箱即用 - 别在
publish()时传null或空字符串,Redis 会忽略 - 频道名(channel)区分大小写,发布和订阅必须完全一致,包括空格
如何注册MessageListener并确保它真正生效?
光写个类实现 MessageListener 接口没用,Spring 不会自动注册。必须显式配置 RedisMessageListenerContainer,并把 listener 和 channel 绑定进去。常见错误是漏掉容器的 setConnectionFactory,或没调用 container.afterPropertiesSet()(如果手动 new 容器)。
更稳妥的做法是用 @Bean 声明容器,并通过 addMessageListener() 注册监听器:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
@Bean
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory factory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(factory);
container.addMessageListener(new MyMessageListener(), new PatternTopic("my-channel"));
return container;
}
- 用
PatternTopic支持通配符(如"log.*"),用ChannelTopic匹配精确频道 - 监听器方法
onMessage()运行在独立线程,不能直接依赖 request scope bean - 如果应用启用了多个 profile,确认当前 profile 下 Redis 连接配置已加载
消息丢失或重复消费怎么排查?
Redis 的 Pub/Sub 是纯内存、无持久化的机制,断连期间发布的消息一定丢失;也没有 ACK 机制,所以“重复消费”通常不是 Redis 导致的,而是监听器抛异常后容器重试(取决于具体 container 配置),或者业务代码里手动重复调用了 publish()。
- 检查日志里是否有
SubscriptionException或连接中断记录 - 不要在
onMessage()里做耗时操作(比如远程调用),否则会阻塞该 listener 的整个线程池 - 若需可靠性,得换方案:用 Redis Streams + consumer group,或切到 RabbitMQ/Kafka
- 测试时用
redis-cli subscribe my-channel直接验证底层通路是否正常,绕过 Spring 层
Spring Boot 2.6+ 中 RedisMessageListenerContainer 自动配置被禁用了?
从 Spring Boot 2.6 开始,RedisMessageListenerContainer 的自动配置(RedisAutoConfiguration)默认关闭了,因为多数 Web 应用并不需要它,且容易因未配监听器导致启动失败。如果你没手动声明容器 bean,应用能启动但不会监听任何频道。
- 必须显式定义
@Bean RedisMessageListenerContainer,哪怕只是空壳 - 如果项目用了 Spring Session,它可能自带一个 container,注意别冲突
- 启用 debug 日志(
logging.level.org.springframework.data.redis=DEBUG)能看到 container 是否注册了 listener 和 topic
Pub/Sub 在 Redis 里轻量、低延迟,但也仅限于此——它不是消息队列,没有堆积、重试、顺序保证这些概念。想靠它做订单通知或支付回调,十有八九后期要重构。

















