Spring整合Redis应用篇(四、延迟消费之监听Key失效事件)

工作中,延迟消费的场景也是挺常见的,比如支付订单30分钟未支付取消,点餐、打车10分钟无人接自动取消等,延迟消费单应用环境可以使用JDK的DelayQueue来实现,分布式环境就要引入三方组件来实现了,可以实现的有 MQ,Redis等,本文教大家用 Redis的监听key超时来实现延迟消费,

如:生成订单时,将订单作为key写入redis,并设置超时时间,如果订单支付就删除这个key(删除并不会触发key的自动失效事件),如无后续操作,就会在等待30分钟后,触发key的超时事件,进入我们设置的业务后续处理流程。

需要注意的是,这样做很危险,消费方一旦宕机,这个key事件就相当于被略过了,而且我们也无从得知了,如搭建高可用的集群环境消费的话,需要注意不要被重复消费了。

要监听redis的key失效,首先需要开启redis的相关配置,如下,默认是被注释掉的

pom yaml 略,同上文无变化,配置类如下,注释掉上文无关内容,大家看变化

@AllArgsConstructor
@SpringBootConfiguration
public class RedisPubsubConfig {

    private final RedisConnectionFactory redisConnectionFactory;

    // 依赖搜索
    // private final List<RedisMessagePublisher> redisMessagePublisherList;

    // redis消息监听器容器
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        // 统一注册redis消息监听器
        // redisMessagePublisherList.forEach(redisMessagePublisher -> container.addMessageListener(redisMessagePublisher, redisMessagePublisher.subTopic()));
        return container;
    }

    // 监听redis key失效事件
    @Bean
    public KeyExpirationEventMessageListener keyExpiredListener(RedisMessageListenerContainer redisMessageListenerContainer) {
        /**
         * 监听器已由spring实现,接收到redis key失效事件时,会发布一个spring容器事件RedisKeyExpiredEvent
         * {@link org.springframework.data.redis.connection.MessageListener}
         */
        return new KeyExpirationEventMessageListener(redisMessageListenerContainer);
    }

    @EventListener(RedisKeyExpiredEvent.class)
    public void callback(RedisKeyExpiredEvent redisKeyExpiredEvent) {
        /*
         * 此处可以拿到失效的key,拿不到已经失效的key的value值,追到顶层接口
         * org.springframework.data.redis.connection.MessageListener#onMessage也没看到
         * 拿不到value的话,可操作性就没那么大了,比如,对于一个取消订单操作,生成的方式不同,取
         * 消时的逻辑也是有所差异,我们可以key存订单,value存订单类型(微信支付/支付宝支付等)
         * ,这里拿不到value的话,也就不那么方便了,虽然也可以拼串存key里,处理起来不仅麻烦也不
         * 够“优雅”,哈哈,大家要是知道怎么拿到失效key的value可以告诉下我哈
         */ 
        // id 是key
        byte[] id = redisKeyExpiredEvent.getId();
        System.out.println("id:" + new String(id, StandardCharsets.UTF_8));
       
        // source 也是key
        byte[] source = redisKeyExpiredEvent.getSource();
        System.out.println("source:" + new String(source, StandardCharsets.UTF_8));
        
        // 不知道是啥,null,反正也不关心
        String keyspace = redisKeyExpiredEvent.getKeyspace();
        System.out.println("keyspace:" + keyspace);
        
        // 应该是失效key的value吧?但是是null
        Object value = redisKeyExpiredEvent.getValue();
        System.out.println("value:" + value);
        
        // 时间戳
        long timestamp = redisKeyExpiredEvent.getTimestamp();
        System.out.println("timestamp:" + timestamp);
    }
}

简单的贴一下测试结果:

设置一个key,10s后超时

 10s后,我们写的监听事件被被执行,打印结果如下:


版权声明:本文为qq_40553917原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。