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; } }