RedisMessageListenerContainer需手动声明为Bean,监听器必须实现MessageListener接口并通过addMessageListener()方法注册。为保证数据正确,序列化方式需与发布端完全一致,推荐统一使用StringRedisTemplate。发布端调用convertAndSend()发送消息时,需注意异常处理,例如添加
Spring Boot Redis发布订阅配置RedisMessageListenerContainer
时间:2026-07-20
浏览:435
文章目录
RedisMessageListenerContainer 得自己手动声明 Bean,Spring Boot 2.0+ 不会自动帮你配好;监听器要实现 MessageListener,通过 addMessageListener() 手工注册,别指望 @EventListener 能管用;序列化必须跟发布端保持一致,最省心的做法是统一用 StringRedisTemplate。

手动声明 RedisMessageListenerContainer Bean 是 Spring Boot 2.0+ 的必备配置
Spring Boot 2.0+ 默认不会自动创建 RedisMessageListenerContainer——即使你已经正确引入了 spring-boot-starter-data-redis 并配置好了 RedisConnectionFactory,它依然不会自动生效。如果没有显式地声明一个 Bean,那么 @EventListener 或者你自己编写的监听器类都不会被触发,订阅逻辑就会静默失效。
一个典型的踩坑现场:启动日志中看不到 “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 消息——实际上永远收不到。
实操建议:
- 监听器要实现
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。因此外层最好捕获并处理异常,不要天真地认为“消息发出去就一定能到达”。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。