redismessagelistenercontainer 必须手动声明 bean,spring boot 2.0+ 不自动配置;监听器需实现 messagelistener 并通过 addmessagelistener() 注册,不可用 @eventlistener;序列化需与发布端一致,推荐统一使用 stringredistemplate。

RedisMessageListenerContainer 配置必须手动声明 Bean
Spring Boot 2.0+ 默认不自动配置 RedisMessageListenerContainer,哪怕你引入了 spring-boot-starter-data-redis 并配好了 RedisConnectionFactory。不显式定义这个 Bean,@EventListener 或监听器类根本不会被注册,订阅行为静默失效。
常见错误现象:RedisMessageListenerContainer 没有启动日志(如 “Starting RedisMessageListenerContainer”),发布消息后监听器无任何响应,也没有报错。
正确做法是手动声明 Bean,并确保它依赖已配置的 RedisConnectionFactory:
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setTaskExecutor(new ThreadPoolTaskExecutor()); // 避免阻塞主线程
return container;
}
监听器注册要用 addMessageListener(),不是 @EventListener
Spring 的 @EventListener 只适用于 Spring 事件(ApplicationEvent),对 Redis 发布/订阅消息完全无效。必须通过 RedisMessageListenerContainer.addMessageListener() 显式注册监听器实例。
典型误区:写一个带 @Component 和 @EventListener 的类,以为能收到 Redis 消息——结果永远收不到。
实操建议:
Redis 8.2.3 是一款安全优先的高性能键值存储系统。该版本紧急修复了可能引发远程代码执行(RCE)的高危漏洞(CVE-2025-62507),并解决了 HyperLogLog 及 Cuckoo Filter 等数据结构在特定场景下的崩溃问题。建议所有用户立即升级,以保障生产环境的系统稳定与数据安全。
- 监听器需实现
MessageListener接口(或继承KeyExpirationEventMessageListener等子类) - 用
PatternTopic订阅通配符频道(如PatternTopic("user:*")),用ChannelTopic订阅精确频道(如ChannelTopic("user.login")) - 注册时传入监听器实例和 Topic 列表,例如:
container.addMessageListener(myListener, new ChannelTopic("order.created"))
消息序列化问题常导致 onMessage() 收到 null 或乱码
默认 RedisMessageListenerContainer 使用 JdkSerializationRedisSerializer,但如果你的生产者用的是 StringRedisTemplate(即 StringRedisSerializer),两边序列化方式不一致,onMessage(Message, byte[]) 中的 message.getBody() 会是乱码或空字节数组。
解决方案取决于你的使用场景:
- 统一用
StringRedisTemplate:配置容器时设置setTopicSerializer(new StringRedisSerializer())(注意:该方法仅在 Spring Data Redis 2.6+ 可用) - 降级兼容老版本:自定义
MessageListener,在onMessage()内手动用new String(message.getBody(), StandardCharsets.UTF_8)解码 - 避免混用:不要让
RedisTemplate和StringRedisTemplate对同一组频道收发消息
发布端必须用 RedisTemplate 或 StringRedisTemplate 的 convertAndSend()
不能用 execute() + 原生 PUBLISH 命令绕过序列化逻辑,否则监听器收到的消息体无法被反序列化(尤其当容器配置了非默认序列化器时)。
正确发布方式只有两个:
-
redisTemplate.convertAndSend("channel.name", "hello")—— 要求redisTemplate的 value serializer 与监听器解码方式匹配 -
stringRedisTemplate.convertAndSend("channel.name", "hello")—— 最简单,推荐用于纯字符串消息
容易忽略的一点:convertAndSend() 是异步非阻塞的,但若连接池耗尽或 Redis 不可用,它会抛出 RedisConnectionFailureException,需在外层捕获并处理,而不是假设“发了就一定到”。










