spring boot 集成redis监听Key值事件失效
有時(shí)需要監(jiān)聽(tīng)Redis的事件從而在Redis事件發(fā)生時(shí)添加一些后續(xù)操作;在實(shí)際開(kāi)發(fā)過(guò)程中,有這么一個(gè)需求,監(jiān)聽(tīng)Redis中的鍵狀態(tài),從而去更改程序中數(shù)據(jù)的狀態(tài);實(shí)現(xiàn)方法如下:
-
方法一: 實(shí)現(xiàn)redis提供的MessageListener接口
首先開(kāi)啟Redis的監(jiān)聽(tīng)事件,大約在Redis配置文件的889行,或者直接搜索notify-keyspace-events,將其更改為你需要監(jiān)聽(tīng)的類型
這段注釋已經(jīng)寫得非常清楚了,建議想了解配置詳情的哥們可以把下面這部分注釋復(fù)制粘貼到翻譯軟件中自己理解,如果急于功能實(shí)現(xiàn)的話,那么就把notify-keyspace-events屬性設(shè)置為EA
# Redis can notify Pub/Sub clients about events happening in the key space. # This feature is documented at http://redis.io/topics/notifications # # For instance if keyspace events notification is enabled, and a client # performs a DEL operation on key "foo" stored in the Database 0, two # messages will be published via Pub/Sub: # # PUBLISH __keyspace@0__:foo del # PUBLISH __keyevent@0__:del foo # # It is possible to select the events that Redis will notify among a set # of classes. Every class is identified by a single character: # # K Keyspace events, published with __keyspace@<db>__ prefix. # E Keyevent events, published with __keyevent@<db>__ prefix. # g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... # $ String commands # l List commands # s Set commands # h Hash commands # z Sorted set commands # x Expired events (events generated every time a key expires) # e Evicted events (events generated when a key is evicted for maxmemory) # A Alias for g$lshzxe, so that the "AKE" string means all the events. # # The "notify-keyspace-events" takes as argument a string that is composed # of zero or multiple characters. The empty string means that notifications # are disabled. # # Example: to enable list and generic events, from the point of view of the # event name, use: # # notify-keyspace-events Elg # # Example 2: to get the stream of the expired keys subscribing to channel # name __keyevent@0__:expired use: # notify-keyspace-events EA # # By default all notifications are disabled because most users don't need # this feature and the feature has some overhead. Note that if you don't # specify at least one of K or E, no events will be delivered. # notify-keyspace-events ""其次需要實(shí)現(xiàn)MessageListener接口
@Component @Slf4j public class MyMessageListener implements MessageListener{@Overridepublic void onMessage(Message message, byte[] bytes) {log.debug("鍵值{}",message.toString());} }然后需要在配置類中將這個(gè)事件監(jiān)聽(tīng)添加到Redis容器中
@Configuration public class Configurer{@BeanMyMessageListener myMessageListener(){new MyMessageListener();}@BeanRedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,MyMessageListener myMessageListener) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(connectionFactory);container.addMessageListener(myMessageListener,new PatternTopic("__keyevent@*__:expired"))return container;}} -
方法二: 繼承redis提供的KeyExpirationEventMessageListener類
@Component @Slf4j public class MyRedisKeyExpirationListener extends KeyExpirationEventMessageListener {public MyRedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {super(listenerContainer);}@Overridepublic void onMessage(Message message, byte[] pattern) {log.debug("鍵值{}",message.toString());} }這種方法省去了將監(jiān)聽(tīng)器添加到容器中的步驟,因?yàn)樵贙eyExpirationEventMessageListener類中它已經(jīng)將監(jiān)聽(tīng)添加到容器中
private static final Topic KEYEVENT_EXPIRED_TOPIC = new PatternTopic("__keyevent@*__:expired");protected void doRegister(RedisMessageListenerContainer listenerContainer) {listenerContainer.addMessageListener(this, KEYEVENT_EXPIRED_TOPIC); }集成KeyExpirationEventMessageListener類無(wú)疑是一種簡(jiǎn)單的模式,但是它只能監(jiān)聽(tīng)key失效的情況,于是我參考方法一和方法二,將Topic配置交給相應(yīng)的監(jiān)聽(tīng)器實(shí)現(xiàn)如下:
-
方法三
public abstract class AbstractMessageListener implements MessageListener, InitializingBean {private final RedisMessageListenerContainer listenerContainer;protected AbstractMessageListener(RedisMessageListenerContainer listenerContainer) {this.listenerContainer = listenerContainer;}public void afterPropertiesSet() throws Exception {listenerContainer.addMessageListener(this, getTopic());}protected abstract Topic getTopic(); }通過(guò)實(shí)現(xiàn)上面的抽象接口從而實(shí)現(xiàn)監(jiān)聽(tīng)格式和事件的注冊(cè)關(guān)系
@Slf4j public class KeyExpirationMessageListener extends AbstractMessageListener {public KeyExpirationMessageListener(RedisMessageListenerContainer listenerContainer, List<KeyHandle> keyHandleList) {super(listenerContainer);}@Overrideprotected Topic getTopic() {return new PatternTopic("__keyevent@*__:expired");}@Overridepublic void onMessage(Message message, byte[] bytes) {log.debug("鍵值{}",message.toString());} }
那么問(wèn)題來(lái)了:在項(xiàng)目開(kāi)始運(yùn)行時(shí),方法三可以順利的運(yùn)行并沒(méi)有任何問(wèn)題;但是在將Redis服務(wù)重啟后事件監(jiān)聽(tīng)竟然毫無(wú)反應(yīng)。當(dāng)我把方法二的代碼啟用后,程序又可以順利的運(yùn)行。當(dāng)時(shí)因?yàn)橹碧幚砥渌鼏?wèn)題,所以當(dāng)程序順利運(yùn)行后就沒(méi)有再管這個(gè)問(wèn)題;又過(guò)了一段安然的日子,Redis重啟后,又出現(xiàn)了這個(gè)尷尬的問(wèn)題,這時(shí)我決定將它徹徹底底的消滅掉,于是我在想,難道Redis只認(rèn)自己的親兒子?當(dāng)然這么可笑的想法只是一閃而過(guò),親兒子特殊肯定有特殊的地方,于是我開(kāi)始考慮是不是KeyExpirationEventMessageListener類中做了什么特殊的處理;說(shuō)干就干,我打開(kāi)了它的源碼,沒(méi)有任何特殊的地方,又打開(kāi)了它的爸爸KeyspaceEventMessageListener類,果然一份驚喜在等著我
private String keyspaceNotificationsConfigParameter = "EA";public void init() {if (StringUtils.hasText(this.keyspaceNotificationsConfigParameter)) {RedisConnection connection = this.listenerContainer.getConnectionFactory().getConnection();try {Properties config = connection.getConfig("notify-keyspace-events");if (!StringUtils.hasText(config.getProperty("notify-keyspace-events"))) {connection.setConfig("notify-keyspace-events", this.keyspaceNotificationsConfigParameter);}} finally {connection.close();}}this.doRegister(this.listenerContainer); }notify-keyspace-events這個(gè)屬性我們不太陌生,這個(gè)值有個(gè)特性就是當(dāng)它的設(shè)置值為空值時(shí)則默認(rèn)是不啟用事件的,但是這個(gè)類在它為空的時(shí)候設(shè)置了默認(rèn)值。這可能就是我們方法三中的類不受支持的原因。于是我打開(kāi)Redis配置文件,此時(shí)它是這樣的,為了能更清楚的展示出我傻逼的一面,我用截圖來(lái)說(shuō)明一下問(wèn)題:
現(xiàn)在問(wèn)題已經(jīng)找到了,我在將notify-keyspace-events設(shè)置成我想要的值之后,沒(méi)有將默認(rèn)配置注釋掉!沒(méi)有將默認(rèn)配置注釋掉!沒(méi)有將默認(rèn)配置注釋掉!于是我決定把這次傻逼行為記錄下來(lái),不斷的提醒自己
細(xì)節(jié)不僅能打敗愛(ài)情,也能打敗程序員!!!!!
順便再說(shuō)一句,在翻看源碼的時(shí)候,我發(fā)現(xiàn),還有一種方法可以實(shí)現(xiàn)事件監(jiān)聽(tīng),那就是直接實(shí)現(xiàn)KeyExpirationEventMessageListener的爸爸KeyspaceEventMessageListener類,但是它的名字已經(jīng)標(biāo)記了它是監(jiān)聽(tīng) __keyspace事件,不知道為什么程序里監(jiān)聽(tīng)的是 __keyevent事件,我想這可能就是大佬吧,讓你琢磨不透
原文章地址請(qǐng)點(diǎn)擊此處鏈接
總結(jié)
以上是生活随笔為你收集整理的spring boot 集成redis监听Key值事件失效的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 免费的.netFramework 混淆工
- 下一篇: 可数集