如何在Spring Boot项目中基于Redisson Reactive API配置键过期事件监听器
Spring Boot WebFlux集成Redisson实现全量键过期事件监听失效解决方案
1. 确认Redis服务端键空间通知配置已开启
Redis默认关闭键事件通知能力,未开启该配置时不会产生任何过期事件消息,两种配置方式:
- 临时生效(Redis重启后失效):在Redis客户端执行命令
config set notify-keyspace-events Ex
说明:参数E代表发送键事件通知,x代表发送过期事件,二者组合才会生成__keyevent@*__:expired对应的事件消息 - 永久生效:修改redis.conf配置文件,添加/修改配置项
notify-keyspace-events Ex,修改后重启Redis服务生效
2. Redisson监听代码调整
原写法存在两个常见问题:一是未持有监听器实例/订阅ID可能导致被GC回收,二是未纳入Spring生命周期管理可能出现订阅动作未执行/RedissonClient实例异常的问题,修正后代码示例:
import org.redisson.api.RTopic; import org.redisson.api.RedissonClient; import org.redisson.client.codec.StringCodec; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @Component public class RedisKeyExpireListener { // 持有订阅ID避免监听器被GC回收 private int expireListenerId; private final RedissonClient redissonClient; // 注入Spring容器管理的RedissonClient实例,避免使用手动创建的实例 public RedisKeyExpireListener(RedissonClient redissonClient) { this.redissonClient = redissonClient; } // 应用启动完成后自动执行订阅 @PostConstruct public void subscribeExpireEvent() { RTopic expiredTopic = redissonClient.getTopic("__keyevent@*__:expired", StringCodec.INSTANCE); expireListenerId = expiredTopic.addListener(String.class, (channel, expiredKey) -> { // 此处编写业务逻辑,expiredKey为过期的键名 // *注意:WebFlux环境下不要在该回调中执行阻塞操作,阻塞逻辑需切换到响应式线程池调度* System.out.println("监听到过期键:" + expiredKey); }); } // 应用销毁时主动取消订阅,避免资源泄漏 @PreDestroy public void unsubscribeExpireEvent() { RTopic expiredTopic = redissonClient.getTopic("__keyevent@*__:expired", StringCodec.INSTANCE); expiredTopic.removeListener(expireListenerId); } }
3. 其他场景问题排查
- 若使用Redis集群模式:需给所有集群节点都开启键空间通知配置,过期事件由键实际存储的节点产生
- 若只使用固定Redis库:可以将Topic通配符
*替换为具体的库编号,例如__keyevent@0__:expired,减少无效消息接收 - 检查网络策略:确认Redis服务端防火墙、安全组未阻挡pub/sub消息的传输端口
- 过期延迟说明:Redis采用惰性删除+定期删除策略清理过期键,事件触发存在秒级延迟属于正常现象
内容的提问来源于stack exchange,提问作者akil nishman
相关产品推荐
相关产品推荐

