You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.1迁移后Redis消息监听器无法启动求助

Spring Boot 3.1 + Spring Data Redis 3.1 迁移后Redis消息监听器启动失败问题

将Spring Boot从2.6.2版本迁移至3.1版本,同步升级spring-data-redis至3.1版本后,遇到Redis消息监听器Bean无法启动的问题。

报错信息

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'jedisMessageListenerContainer'","logger_name":"org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"}

相关配置

Redis消息监听器容器Bean配置

@Bean
RedisMessageListenerContainer jedisMessageListenerContainer(JedisConnectionFactory jedisConnectionFactory,
                                                            RedisKeyExpirationListener redisListener) {
    RedisMessageListenerContainer container = new RedisMessageListenerContainer();
    container.setConnectionFactory(jedisConnectionFactory);
    container.addMessageListener(redisListener, new PatternTopic(
            "__keyevent@0__:expired"));
    container.setErrorHandler(e -> log.error("There was an error in redis key expiration listener container", e));
    return container;
}

其中RedisKeyExpirationListener实现了spring-data-redis中的MessageListener接口。

Jedis连接工厂配置

当前使用Jedis 4.4.2(也曾测试兼容的4.3.2版本)作为连接客户端,spring-boot-starter-data-redis版本为3.1.0,连接工厂实现如下:

@Bean
public JedisPoolConfig jedisPoolConfig() {
    var jedisPoolConfig = new JedisPoolConfig();
    jedisPoolConfig.setMaxTotal(10);
    jedisPoolConfig.setMinIdle(0);
    jedisPoolConfig.setMaxIdle(8);
    return jedisPoolConfig;
}

@Bean
public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
    var jedisClientConfiguration = JedisClientConfiguration.builder()
            .usePooling()
            .poolConfig(jedisPoolConfig)
            .and()
            .readTimeout(Duration.ofMillis(1000L))
            .useSsl()
            .build();
    // 注:原代码未完整展示连接工厂的Redis配置(如主机、端口等),此处保留原文结构
}

调试与测试发现

  • 调试发现RedisMessageListenerContainer捕获TimeoutException后抛出:
    IllegalStateException("Subscription registration timeout exceeded", e);
    
    该异常后续被Bean处理器转换为"Failed to start bean"异常。
  • 尝试将容器的MaxSubscriptionRegistrationWaitingTime调至最长60秒,仍触发相同异常。
  • 移除RedisMessageListenerContainer上的addMessageListener调用后,应用可正常连接Redis;仅添加消息监听器时出现问题。
  • 回退至Spring Boot 2.6.2及对应版本spring-data-redis时,消息监听器可正常工作并处理过期事件。

已尝试的解决方法

  • 更新Jedis、Spring Boot、spring-data-redis及spring-boot-starter-data-redis至Spring Boot 3兼容的最新版本;
  • 增大连接池配置参数及超时时间;
  • 移除监听器验证应用可用性(无监听器时可正常运行);
  • 改用MessageListenerAdapter实现,让RedisKeyExpirationListener实现自定义MessageDelegate接口而非MessageListener接口,配置如下:
    @Bean
    RedisKeyExpirationListener redisListener() {
        return new RedisKeyExpirationListener();
    }
    
    @Bean
    MessageListenerAdapter redisListenerAdapter(RedisKeyExpirationListener redisListener) {
        return new MessageListenerAdapter(redisListener, "handleMessage");
    }
    
    @Bean
    RedisMessageListenerContainer jedisMessageListenerContainer(JedisConnectionFactory jedisConnectionFactory,
                                                                MessageListenerAdapter redisListenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(jedisConnectionFactory);
        container.addMessageListener(redisListenerAdapter, new PatternTopic(
                "__keyevent@0__:expired"));
        container.setErrorHandler(e -> log.error("There was an error in redis key expiration listener container", e));
        return container;
    }
    
    自定义接口:
    public interface MessageDelegate {
        void handleMessage(String message);
        void handleMessage(Message message, byte[] pattern);
    }
    

请求协助

请协助排查该问题的根本原因及可行的解决方法。

内容的提问来源于stack exchange,提问作者Michał Lipski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 02:13:19