前言
试想一个业务场景,订单超过30分钟未支付需要做自动关单处理,修改订单状态,库存回退等,你怎么实现?方案一:可以使用定时任务扫表,通过支付状态和下单时间来判断是否支付过期。但是这样的方案是非常消耗性能的,因为大部分的定时扫表都是无效的,而且这种定时任务方案对于时间控制并不精确。
类似的业务场景还很多,比如物流自动收货确认,比如某电影上线预约功能的到时提醒等等,对于这些问题有没有比定时任务更优雅的处理方案呢?
RabbitMQ的延迟队列,可以用来解决这种业务场景,那如果项目中并没有用到RabbitMQ,为了搞一个延迟队列而使用RabbitMQ未免太麻烦,那么本篇文章《Redis监听key过期事件》就可以代替RabbitMQ的延迟队列来处理类似的场景。
开启key过期事件
在redis.conf配置文件中有个配置项:notify-keyspace-events " " ,默认是没有key的过期监听的,我们需要将其开启,如下:
这里的 EX代表 expire 和 evicted 过期和驱逐 的时间监听 ,注意:改了配置要重启Redis
创建SpringBoot工程
创建SpringBoot项目,导入Redis依赖
<!--整合Redis , 底层可以用jedis--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
然后做yml配置,Redis基本配置
spring: redis: database: 0 host: 127.0.0.1 port: 6379 password: 123456 jedis: pool: max-wait: 2000ms min-idle: 2 max-idle: 8
…其他不重要代码这里就省略了…
配置Redis监听器
注册 RedisMessageListenerContainer ,为Redis消息侦听器提供异步行为的容器
@Configuration public class RedisConfig { @Bean RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) { //Redis消息监听器 RedisMessageListenerContainer container = new RedisMessageListenerContainer(); //设置Redis链接工厂 container.setConnectionFactory(connectionFactory); return container; } }
定义key过期的监听器 通过继承 KeyExpirationEventMessageListener 来完成
//消息过期监听器 @Slf4j @Component public class RedisExpireListener extends KeyExpirationEventMessageListener { public RedisExpireListener(RedisMessageListenerContainer listenerContainer) { super(listenerContainer); } //当消息过期,触发方法 @Override public void onMessage(Message message, byte[] pattern) { String expiredKey = message.toString(); System.out.println("Key -> "+expiredKey +"过期了..."); } }
测试
使用redis-cli 设置一个带过期时间的 key ,如:
等待key过期,观察代码控制台
到这里文章就结束了,如果喜欢请给个好评吧!!!