redis 超时失效key 的监听触发
1. 事件经过 Redis 的订阅与发布功能(pub/sub)来进行分发,故须要订阅 __keyevent@0__:expired 通道post
0表示db0 根据本身的dbindex选择合适的数字测试
2. 修改 redis.conf 文件
修改 notify-keyspace-events Ex
# K 键空间通知,以__keyspace@<db>__为前缀 # E 键事件通知,以__keysevent@<db>__为前缀 # g del , expipre , rename 等类型无关的通用命令的通知, ... # $ String命令 # l List命令 # s Set命令 # h Hash命令 # z 有序集合命令 # x 过时事件(每次key过时时生成) # e 驱逐事件(当key在内存满了被清除时生成) # A g$lshzxe的别名,所以”AKE”意味着全部的事件
3. 重启redis , 便可测试失效事件的触发, 监听获取的值为 key
<java>
4. 首先须要一个消息监听器类 RedisSubListener
RedisSubListener.java
package cn.maitian.maimai.cache.message.sub; import cn.maitian.bss.duty.privilege.utils.SpringContextHolder; import cn.maitian.maimai.cache.client.MaimaiJedis; import cn.maitian.maimai.cache.keys.RedisKeys; import cn.maitian.maimai.cache.model.RedisKeyspaceNotifiRecord; import cn.maitian.maimai.cache.service.RedisKeyspaceNotifiRecordIService; import cn.maitian.maimai.core.exception.AppSysException; import cn.maitian.maimai.core.util.AppStringUtils; import cn.maitian.maimai.schedule.utils.JobUtils; import com.alibaba.fastjson.JSONObject; import org.apache.log4j.Logger; import redis.clients.jedis.JedisPubSub; import java.util.Date; /** * Redis 发布订阅模型(Pub/Sub)的订阅服务监听器 * * @author * @version V1.0 * @company * @date */ public class RedisSubListener extends JedisPubSub { /** * 日志 */ protected final Logger logger = Logger.getLogger(getClass()); private RedisKeyspaceNotifiRecordIService redisKeyspaceNotifiRecordIService; /** * * @Title: onMessage * @Description: 取得订阅的消息后的处理 * @param channel * 频道 * @param message * 消息内容 * * @author * @date */ @Override public void onMessage(String channel, String message) { logger.info("channel{" + channel + "}message{" + message + "}"); } /** * * @Title: onPMessage * @Description: 取得按表达式的方式订阅的消息后的处理 * * @author * @date */ public void onPMessage(String pattern, String channel, String message) { logger.info("Redis订阅监听超时通知开始pattern{" + pattern + "}channel{" + channel + "}message{" + message + "}"); long starTime = System.currentTimeMillis(); if (AppStringUtils.isEmpty(message)) { logger.info("Redis订阅监听超时通知,message为空"); return; } RedisKeyspaceNotifiRecord record = null; String keyId; try { if (message.startsWith(RedisKeys.REDIS_LOCK_KEY_STRING)) { logger.info("Redis订阅监听超时通知,此key值不须要进行订阅处理"); return; } keyId = message.substring(message.lastIndexOf(":") + 1); long result = MaimaiJedis.setnx(RedisKeys.REDIS_LOCK_KEY_STRING + keyId,RedisKeys.REDIS_LOCK_KEY_STRING + keyId); if (result==0) { logger.info("Redis订阅监听超时通知,此key已被设置,请勿重复设置"); return; } record = redisKeyspaceNotifiRecordIService.findById(keyId); if (record == null) { // throw new AppSysException("Redis订阅监听超时通知,找不到记录id{" + keyId + "}"); logger.error("Redis订阅监听超时通知,找不到记录id{" + keyId + "}"); return; } record.setBeginTime(new Date()); if (AppStringUtils.isEmpty(record.getServiceClass())) { throw new AppSysException("Redis订阅监听超时通知,RedisKeyspaceNotifiRecord中必须包含ServiceClass"); } Object object = SpringContextHolder.getBean(Class.forName(record.getServiceClass())); String serviceMethod = record.getServiceMethod(); Object[] params; if (AppStringUtils.isEmpty(record.getServiceParams())) { params = new Object[] {}; } else { params = JSONObject.parseArray(record.getServiceParams()).toArray(); } if (object != null && !AppStringUtils.isEmpty(serviceMethod)) { JobUtils.invokeMethod(object, serviceMethod, params); record.setStatus(RedisKeyspaceNotifiRecord.STATUS_SUCCESS_EXECUTE);// 执行成功 } } catch (AppSysException e) { if (record != null) { record.setStatus(RedisKeyspaceNotifiRecord.STATUS_FAIL_EXECUTE);// 执行失败 } e.printStackTrace(); logger.info("Redis订阅监听超时通知,出现异常{" + e.getCode() + "}", e); } catch (Exception e) { if (record != null) { record.setStatus(RedisKeyspaceNotifiRecord.STATUS_FAIL_EXECUTE);// 执行失败 } e.printStackTrace(); logger.info("Redis订阅监听超时通知,出现异常", e); } finally { if (record != null) { record.setEndTime(new Date()); redisKeyspaceNotifiRecordIService.saveOrUpdate(record); } } long endTime = new Date().getTime(); logger.info("Redis订阅监听超时通知完成pattern{" + pattern + "}channel{" + channel + "}message{" + message + "}共耗时{" + (endTime - starTime) / 1000 + "}秒"); } /** * @param redisKeyspaceNotifiRecordIService * the redisKeyspaceNotifiRecordIService to set */ public void setRedisKeyspaceNotifiRecordIService( RedisKeyspaceNotifiRecordIService redisKeyspaceNotifiRecordIService) { this.redisKeyspaceNotifiRecordIService = redisKeyspaceNotifiRecordIService; } }
5.Redis订阅指定的频道(此类用于订阅Redis的键值超时事件)
RedisKeySpaceNotification.java
package cn.maitian.maimai.cache.message.sub; import cn.maitian.maimai.cache.client.MaimaiJedis; import org.apache.log4j.Logger; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; /** * Redis订阅指定的频道(此类用于订阅Redis的键值超时事件) * * @author * @version V1.0 * @company * @date */ public class RedisKeySpaceNotification implements InitializingBean, DisposableBean { /** * 是否开启Redis键值超时通知服务(默认打开) */ private static boolean isRedisActiveKeySpaceNotification = true; /** * 日志 */ protected final Logger logger = Logger.getLogger(getClass()); private RedisSubListener redisSubListener; @Override public void destroy() throws Exception { // 销毁 } @Override public void afterPropertiesSet() throws Exception { if (isRedisActiveKeySpaceNotification) { logger.error("Redis订阅的键值超时事件已启动-----------------------------------"); JedisPool jedisPool = MaimaiJedis.getMaiMaiJedisPool(); final Jedis jedis = jedisPool.getResource(); new Thread(new Runnable() { @Override public void run() { jedis.psubscribe(redisSubListener, "__keyevent@*__:expired"); } }).start(); } } /** * @param redisSubListener * the redisSubListener to set */ public void setRedisSubListener(RedisSubListener redisSubListener) { this.redisSubListener = redisSubListener; } }