栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

监听Redis 缓存过期(Key 失效)事件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

监听Redis 缓存过期(Key 失效)事件

监听Redis 缓存过期(Key 失效)事件

最近写公司一个项目遇到一个场景,设备上线后会以0.5HZ的频率给后台发送状态消息,20秒内没有重连则认为设备下线,需要执行相应操作。

首先想到的就是在Redis存带过期时间的key,每次设备发来消息就去刷新key的过期时间,key过期后,则执行设备下线的方法,那么问题来了,这怎么去监听key是否过期(当时没听说过redis还可以发布/订阅),于是头脑风暴了一下,直接看Redis监听的可以跳过。

头脑风暴一:

每次设备上线都在在Redis里存储:
	1. 过期时间20秒
	2. 不包含过期时间
开启一个定时任务:每隔30秒去Redis获取一下这两组数据
每组数据都包含多个,因为可能有多个设备在线
对比这两组数据,即可找到过期的数据,也就是下线的设备(id_backup有,id_time已经失效的数据)
然后去执行相应的操作。

但是不太想整个Redis
头脑风暴二

干脆直接在Java中维护一个Map(当然我做的这个项目在线设备不多,百八十个不得了了)
每次设备发送状态信息,刷新一下map里的`最后状态时间戳`
然后开启一个定时任务,每隔30秒去遍历一下map
哪个数据的'最后状态时间戳'比当前时间早了超过30秒则认为设备下线,指向相应操作

这种方法虽然不用整合Redis但是容易导致数据丢失,一旦服务停止,内存中数据不会持久化。

于是网上找了一下相关Redis监听相关方法,还真有,下面我把SpringBoot整合Redis,实现Redis 缓存过期(Key 失效)事件监听相关代码分享

Redis 缓存过期(Key 失效)事件监听 Redis配置修改
  1. 事件通过 Redis 的订阅与发布功能(pub/sub)来进行分发, 故需要开启 redis 的事件监听与发布
  2. 修改 redis.conf 文件(Windows上是redis.windows.conf和redis.windows-service.conf)
notify-keyspace-events Ex
  1. 重启Redis,然后进行下面测试。

  2. 打开redis-cli.exe窗口输入:PSUBSCRIBE __keyevent@*__:expired,窗口先别关闭。

  3. 再打开一个redis-cli.exe窗口,存一个带失效时间的数据setex boy 6 6

    查看第一个窗口,监听到数据失效,即配置成功

  4. 引入pom.xml


    org.springframework.boot
    spring-boot-starter-data-redis

  1. application.yaml配置文件
spring: 
  redis:
    host: localhost
    port: 6379
    password: 
    jedis:
      pool:
        max-active: 0
  1. RedisListenerConfig.java
import org.springframework.beans.factory.annotation.Autowired;
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.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisListenerConfig {

    @Autowired
    private RedisTemplate redisTemplate;

    @Bean
    RedisMessageListenerContainer listenerContainer(RedisConnectionFactory connectionFactory) {
        RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer();
        listenerContainer.setConnectionFactory(connectionFactory);
        return listenerContainer;
    }

    @Bean
    KeyExpirationEventMessageListener redisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        return new RedisKeyExpirationListener(listenerContainer);
    }

    @Bean
    public RedisTemplate redisTemplateInit() {
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

}
  1. RedisKeyExpirationListener.java
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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.Service;

@Slf4j
@Service
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {

    public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
        super(listenerContainer);
    }

    @Override
    public void onMessage(Message message, byte[] pattern) {
        //获取过期的key
        String expireKey = message.toString();

        //信息打印
        log.info("key : {} 失效" ,expireKey);

        //设备下线相关操作
        
    }

}
  1. IRedisService.java
public interface IRedisService {

    
    void setValue(String key, String value);

}
  1. RedisServiceImpl.java
import com.tangyh.lamp.utils.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class RedisServiceImpl implements IRedisService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void setValue(String key, String value) {
        ValueOperations vo = redisTemplate.opsForValue();
        vo.set(key, value);
        redisTemplate.expire(key, Constant.OSD_TIME_OUT, TimeUnit.SECONDS); // 这里指的是30秒后失效
    }

}

有错误之处,或者更好的办法还请评论区指教。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/458668.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号