Redisは、新規、変更、削除、期限切れのイベントをリスニングします.
7934 ワード
前言
プロジェクトでは、キーの削除、変更、期限切れなど、redisのイベントをリスニングする必要があります.期限切れのイベントはネット上では多くの例が参考になりますが、変更や削除のイベントは少ないです.redisはパブリケーションサブスクリプションをサポートしているので、他のイベントタイプも実現できるはずですが、期限切れのイベントリスニングと上記のキースペース通知を組み合わせることで、必要な人が迅速に問題を解決できるようにコードを整理しました.
コード実践
ネット上の例の失効イベントリスニングコードimport com.alibaba.fastjson.JSONObject;
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.Component;
import java.util.Date;
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* redis ,
* @param message message.toString() key
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
String expiredKey = message.toString();
// key
}
}
}
これはspringフレームワークが統合されて実装されていることがわかります.//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.redis.listener;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
import org.springframework.lang.Nullable;
public class KeyExpirationEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {
private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired");
@Nullable
private ApplicationEventPublisher publisher;
public KeyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
protected void doRegister(RedisMessageListenerContainer listenerContainer) {
listenerContainer.addMessageListener(this, KEYEVENT_EXPIRED_TOPIC);
}
protected void doHandleMessage(Message message) {
this.publishEvent(new RedisKeyExpiredEvent(message.getBody()));
}
protected void publishEvent(RedisKeyExpiredEvent event) {
if (this.publisher != null) {
this.publisher.publishEvent(event);
}
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
他にも削除イベントが実現していない場合は、springを真似てこのようなListenerを書くことを考えています.
Redisキースペース通知の概要:リファレンスドキュメントhttp://redisdoc.com/topic/notification.html
キースペース通知、すべての通知はkeyspace@を接頭辞キーイベント通知とし、すべての通知はkeyevent@を接頭辞とするすべてのコマンドはキーが本当に変更された後にのみ通知が発生します.例えば、fooを削除するとキースペース通知「pmessage」、「__key_:」、「_keyspace@0__:foo","set"とキーイベント通知"pmessage","key__:","__ keyevent@0__:set","foo"
あるkeyが実行した操作を傍受する場合は、keyspace@を購読し、ある操作がどのkeyを動かしたかを傍受する場合は、keyevent@を購読します.ここでは、どのキーが削除されたかをリスニングする必要があるので、削除アクションをリスニングします」keyevent@0__:del"
上記springで書いたlistenerに比べてprivate static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired");
という他はモード化されたコードがあり、対応するtopicタイプを修正すればリスニングが可能になります.
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
import org.springframework.data.redis.listener.KeyspaceEventMessageListener;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.lang.Nullable;
public class KeyDeleteEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {
private static final Topic KEYEVENT_DELETE_TOPIC = new PatternTopic("__keyevent@*__:del");
@Nullable
private ApplicationEventPublisher publisher;
public KeyDeleteEventMessageListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
protected void doRegister(RedisMessageListenerContainer listenerContainer) {
listenerContainer.addMessageListener(this, KEYEVENT_DELETE_TOPIC);
}
protected void doHandleMessage(Message message) {
this.publishEvent(new RedisKeyExpiredEvent(message.getBody()));
}
protected void publishEvent(RedisKeyExpiredEvent event) {
if (this.publisher != null) {
this.publisher.publishEvent(event);
}
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
同様の新規作成や修正も同様ですpackage cn.fatri.jarvis.device.shadow.listener;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
import org.springframework.data.redis.listener.KeyspaceEventMessageListener;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.lang.Nullable;
public class KeyUpdateEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {
private static final Topic KEYEVENT_DELETE_TOPIC = new PatternTopic("__keyevent@*__:set");
@Nullable
private ApplicationEventPublisher publisher;
public KeyUpdateEventMessageListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
protected void doRegister(RedisMessageListenerContainer listenerContainer) {
listenerContainer.addMessageListener(this, KEYEVENT_DELETE_TOPIC);
}
protected void doHandleMessage(Message message) {
this.publishEvent(new RedisKeyExpiredEvent(message.getBody()));
}
protected void publishEvent(RedisKeyExpiredEvent event) {
if (this.publisher != null) {
this.publisher.publishEvent(event);
}
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
私たちは同じようにこれらのクラスを継承すれば、傍受のメッセージを手に入れることができます.import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.util.stream.Collectors;
@Component
@Slf4j
public class RedisKeyDeleteListener extends KeyDeleteEventMessageListener {
public RedisKeyDeleteListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* redis ,
* @param message message.toString() key
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
String deleteKey = message.toString();
// ......
}
}
}
ネット上の例の失効イベントリスニングコード
import com.alibaba.fastjson.JSONObject;
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.Component;
import java.util.Date;
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* redis ,
* @param message message.toString() key
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
String expiredKey = message.toString();
// key
}
}
}
これはspringフレームワークが統合されて実装されていることがわかります.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.redis.listener;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
import org.springframework.lang.Nullable;
public class KeyExpirationEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {
private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired");
@Nullable
private ApplicationEventPublisher publisher;
public KeyExpirationEventMessageListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
protected void doRegister(RedisMessageListenerContainer listenerContainer) {
listenerContainer.addMessageListener(this, KEYEVENT_EXPIRED_TOPIC);
}
protected void doHandleMessage(Message message) {
this.publishEvent(new RedisKeyExpiredEvent(message.getBody()));
}
protected void publishEvent(RedisKeyExpiredEvent event) {
if (this.publisher != null) {
this.publisher.publishEvent(event);
}
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
他にも削除イベントが実現していない場合は、springを真似てこのようなListenerを書くことを考えています.
Redisキースペース通知の概要:リファレンスドキュメントhttp://redisdoc.com/topic/notification.html
キースペース通知、すべての通知はkeyspace@を接頭辞キーイベント通知とし、すべての通知はkeyevent@を接頭辞とするすべてのコマンドはキーが本当に変更された後にのみ通知が発生します.例えば、fooを削除するとキースペース通知「pmessage」、「__key_:」、「_keyspace@0__:foo","set"とキーイベント通知"pmessage","key__:","__ keyevent@0__:set","foo"
あるkeyが実行した操作を傍受する場合は、keyspace@を購読し、ある操作がどのkeyを動かしたかを傍受する場合は、keyevent@を購読します.ここでは、どのキーが削除されたかをリスニングする必要があるので、削除アクションをリスニングします」keyevent@0__:del"
上記springで書いたlistenerに比べて
private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired");
という他はモード化されたコードがあり、対応するtopicタイプを修正すればリスニングが可能になります.
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
import org.springframework.data.redis.listener.KeyspaceEventMessageListener;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.lang.Nullable;
public class KeyDeleteEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {
private static final Topic KEYEVENT_DELETE_TOPIC = new PatternTopic("__keyevent@*__:del");
@Nullable
private ApplicationEventPublisher publisher;
public KeyDeleteEventMessageListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
protected void doRegister(RedisMessageListenerContainer listenerContainer) {
listenerContainer.addMessageListener(this, KEYEVENT_DELETE_TOPIC);
}
protected void doHandleMessage(Message message) {
this.publishEvent(new RedisKeyExpiredEvent(message.getBody()));
}
protected void publishEvent(RedisKeyExpiredEvent event) {
if (this.publisher != null) {
this.publisher.publishEvent(event);
}
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
同様の新規作成や修正も同様です
package cn.fatri.jarvis.device.shadow.listener;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
import org.springframework.data.redis.listener.KeyspaceEventMessageListener;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.lang.Nullable;
public class KeyUpdateEventMessageListener extends KeyspaceEventMessageListener implements ApplicationEventPublisherAware {
private static final Topic KEYEVENT_DELETE_TOPIC = new PatternTopic("__keyevent@*__:set");
@Nullable
private ApplicationEventPublisher publisher;
public KeyUpdateEventMessageListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
protected void doRegister(RedisMessageListenerContainer listenerContainer) {
listenerContainer.addMessageListener(this, KEYEVENT_DELETE_TOPIC);
}
protected void doHandleMessage(Message message) {
this.publishEvent(new RedisKeyExpiredEvent(message.getBody()));
}
protected void publishEvent(RedisKeyExpiredEvent event) {
if (this.publisher != null) {
this.publisher.publishEvent(event);
}
}
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}
私たちは同じようにこれらのクラスを継承すれば、傍受のメッセージを手に入れることができます.
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.util.stream.Collectors;
@Component
@Slf4j
public class RedisKeyDeleteListener extends KeyDeleteEventMessageListener {
public RedisKeyDeleteListener(RedisMessageListenerContainer listenerContainer) {
super(listenerContainer);
}
/**
* redis ,
* @param message message.toString() key
* @param pattern
*/
@Override
public void onMessage(Message message, byte[] pattern) {
String deleteKey = message.toString();
// ......
}
}
}