Spring boot实现监听Redis key失效事件
1、添加相关依赖
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置监听(可全部库监听和选一个库监听)
@Configuration
public class RedisListenerConfig {
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
// 选一个库监听则打开下一行的注释
//container.addMessageListener(new RedisExpiredListener(), new PatternTopic("__keyevent@0__:expired"));
return container;
}
}
3.a选一个库监听
/**
* @author mazhq
* @Title: RedisKeyExpirationListener
* @ProjectName: zeus
* @date 2019/2/20 11:26
*/
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
private final static Logger logger = LoggerFactory.getLogger(RedisKeyExpirationListener.class);
@Autowired
private RedisClient redisClient;
/**
* Creates new {@link MessageListener} for {@code __keyevent@*__:expired} messages.
*
* @param listenerContainer must not be {@literal null}.
*/
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
@Override
public void onMessage(Message message, byte[] pattern) {
// 用户做自己的业务处理即可,注意message.t`在这里插入代码片`oString()可以获取失效的key
String expiredKey = message.toString();
if(expiredKey.startsWith("zeus:order")){
//TODO
}
}
}
3.b指定某库监听
public class RedisExpiredListener implements MessageListener {
/**
* 客户端监听订阅的topic,当有消息的时候,会触发该方法;
* 并不能得到value, 只能得到key。
* 姑且理解为: redis服务在key失效时(或失效后)通知到java服务某个key失效了, 那么在java中不可能得到这个redis-key对应的redis-value。
* * 解决方案:
* 创建copy/shadow key, 例如 set vkey "vergilyn"; 对应copykey: set copykey:vkey "" ex 10;
* 真正的key是"vkey"(业务中使用), 失效触发key是"copykey:vkey"(其value为空字符为了减少内存空间消耗)。
* 当"copykey:vkey"触发失效时, 从"vkey"得到失效时的值, 并在逻辑处理完后"del vkey"
*
* 缺陷:
* 1: 存在多余的key; (copykey/shadowkey)
* 2: 不严谨, 假设copykey在 12:00:00失效, 通知在12:10:00收到, 这间隔的10min内程序修改了key, 得到的并不是 失效时的value.
* (第1点影响不大; 第2点貌似redis本身的Pub/Sub就不是严谨的, 失效后还存在value的修改, 应该在设计/逻辑上杜绝)
* 当"copykey:vkey"触发失效时, 从"vkey"得到失效时的值, 并在逻辑处理完后"del vkey"
*
*/
@Override
public void onMessage(Message message, byte[] bytes) {
byte[] body = message.getBody();// 建议使用: valueSerializer
byte[] channel = message.getChannel();
System.out.print("onMessage >> " );
System.out.println(String.format("channel: %s, body: %s, bytes: %s"
,new String(channel), new String(body), new String(bytes)));
}
}