Redis过期事件监听
2025/9/7大约 2 分钟
Redis过期事件监听
启用 Redis 的键空间通知
首先需要在 Redis 配置文件中启用键空间通知。找到或编辑 redis.conf 文件,添加以下配置:
notify-keyspace-events ExE:表示启用键事件(Key event)通知。x:表示启用过期事件(Expired key)通知。
如果使用 Docker 或命令行启动 Redis,可以直接传参:
redis-server --notify-keyspace-events ExJava 客户端配置
在 Spring Boot 项目中,使用 RedisTemplate 和 RedisMessageListenerContainer 来订阅 Redis 的过期事件。
配置 RedisTemplate
确保 RedisTemplate 已正确配置,例如:
/**
* Redis配置类,用于定义Redis相关的Bean和配置
* 包括Redis模板配置和Redis消息监听容器配置
*/
@Configuration
@Slf4j
public class RedisConfig {
/**
* 配置并返回一个RedisTemplate实例
* 用于操作Redis数据库,设置不同的序列化方式
*
* @param factory Redis连接工厂
* @param objectMapper Jackson对象映射器
* @return 配置好的RedisTemplate实例
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory, ObjectMapper objectMapper) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// Key 和 HashKey 使用 String 序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
// Value 使用 Jackson 序列化
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
template.afterPropertiesSet();
log.info("RedisTemplate已成功初始化");
return template;
}
}配置 Redis 消息监听器
编写一个监听器类,实现 MessageListener 接口,处理过期事件:
/**
* 配置并返回一个RedisMessageListenerContainer实例
* 用于监听Redis键过期事件,并处理服务和组的下线逻辑
*
* @param connectionFactory Redis连接工厂
* @return 配置好的RedisMessageListenerContainer实例
*/
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
String database = environment.getProperty("spring.data.redis.database");
Topic topic = new PatternTopic("__keyevent@" + database + "__:expired");
container.addMessageListener((message, pattern) -> {
String expiredKey = new String(message.getBody()); // 获取过期的键
log.info("检测到Redis键过期事件: {}", expiredKey);
if (expiredKey.contains("heartbeat:server")) {
String[] s = expiredKey.split(":");
log.info("服务器心跳过期,标记为离线: {}:{}", s[3], s[4]);
gatewayServerDetailMapper.offline(s[3] + ":" + s[4]);
redisPubUtil.ServerFlush();
} else if (expiredKey.contains("heartbeat:group")) {
String[] s = expiredKey.split(":");
log.info("分组心跳过期,标记为离线: {}:{}", s[3], s[4]);
gatewayGroupDetailMapper.offline(s[3] + ":" + s[4]);
nginxConfUtil.removeInstance(s[3] + ":" + s[4]);
}
}, topic);
log.info("RedisMessageListenerContainer已成功初始化");
return container;
}设置带过期时间的键
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void setHeartbeat(String serviceId, int expireSeconds) {
String key = "heartbeat:group:" + serviceId;
redisTemplate.opsForValue().set(key, "alive", expireSeconds, TimeUnit.SECONDS);
}等待键过期
等待键过期后,监听器会自动触发并打印日志:
过期的键: heartbeat:service:123