简单实现监听redis的Key过期事件

一,背景
公司的订单服务需要实现一个30分钟没付款自动取消的功能, 前面的程序员小弟用了一个定时任务来自动关闭订单,被发现之后,直接fire掉了哈哈哈哈。 这里就用redis来实现一个到时关闭订单的功能。
二,实现
1, 开启redis推送事件的设置
在redis.conf文件中找到EVENT NOTIFICATION部分,找到notify-keyspace-events设置,它的默认值是空字符串,就是不推送事件信息。如果要推送所有信息,就可以设置为Elg, 如果只需要推送key过期事件,就设置为Ex。 这里我们设置为Ex,然后重启redis。

2,添加RedisMessageListenerContainer
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Bean("redisTemplate")public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);// 使用Jackson序列化Jackson2JsonRedisSerializer<Object> serializer =new Jackson2JsonRedisSerializer<>(Object.class);// Key使用String序列化redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());// Value使用JSON序列化redisTemplate.setValueSerializer(serializer);redisTemplate.setHashValueSerializer(serializer);redisTemplate.afterPropertiesSet();return redisTemplate;}@BeanRedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);return container;}
}3,添加Redis事件监听器
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;@Slf4j
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {super(listenerContainer);}/*** 针对redis数据失效事件,进行数据处理** @param message* @param pattern*/@Overridepublic void onMessage(Message message, byte[] pattern) {log.info("Redis key 过期:{}", message);if (message.toString().startsWith("order_")) {// todo: 订单过期, 修改订单状态逻辑} else if (message.toString().contains("user:token:xxxxxxxxxxx")) {log.info("用户token过期,进行用户登出");// todo: 用户登出} else {log.info("其他key过期");}}
}4,生成订单之后,将订单号放入redis,key是order_开始的,这段儿是常规使用redis的操作就省略了。
