springmvc訂閱redis鍵過期訊息通知
首先啟用redis通知功能(ubuntu下操作):
編輯/etc/redis/redis.conf檔案,新增或啟用以下內容(過期通知):
notify-keyspace-events Ex
或者登陸redis-cli之後,輸入以下命令:
config set notify-keyspace-events Ex
因鍵空間通知功能需要耗費一定的CPU時間,因此預設情況下,該功能是關閉的。可以通過修改配置檔案redis.conf,或者通過CONFIG SET命令,設定notify-keyspace-events選項,來啟用或關閉該功能。
該選項的值為空字串時,該功能禁用,選項值為非空字串時,啟用該功能,非空字串由特定的多個字元組成,每個字元表示不同的意義:
K:keyspace事件,事件以[email protected]<db>__為字首進行釋出;
E:keyevent事件,事件以[email protected]<db>__為字首進行釋出;
g:一般性的,非特定型別的命令,比如del,expire,rename等;
$:字串特定命令;
l:列表特定命令;
s:集合特定命令;
h:雜湊特定命令;
z:有序集合特定命令;
x:過期事件,當某個鍵過期並刪除時會產生該事件;
e:驅逐事件,當某個鍵因maxmemore策略而被刪除時,產生該事件;
A:g$lshzxe的別名,因此”AKE”意味著所有事件。
注意,該選項的值中至少需要包含K或者E,否則不會發布任何事件。比如,如果需要開啟針對列表的keyspace事件通知,則該選項需要配置為“Kl”;
expired事件通知的傳送時間
Redis 使用以下兩種方式刪除過期的鍵:
a:當一個鍵被訪問時,程式會對這個鍵進行檢查,如果鍵已過期,則刪除該鍵;
b:系統會在後臺定期掃描並刪除那些過期的鍵;
當過期鍵被以上兩種方式中的任意一種發現並且刪除時,才會產生expired事件通知。
Redis不保證生存時間(TTL)變為 0 的鍵會立即被刪除:如果沒有命令訪問這個鍵,或者設定生存時間的鍵非常多的話,那麼在鍵的生存時間變為0,到該鍵真正被刪除,這中間可能會有一段比較顯著的時間間隔。
因此,Redis產生expired事件通知的時間,是過期鍵被刪除的時候,而不是鍵的生存時間變為 0 的時候。
=========================================================
不同命令產生的事件通知
DEL 命令為每個被刪除的鍵產生一個 del 事件;
RENAME 產生兩個事件:為源鍵產生一個 rename_from 事件,併為目標鍵產生一個 rename_to 事件;
EXPIRE命令,在設定鍵的過期時間時產生一個 expire事件;當鍵因過期而被刪除時,產生一個 expired事件;
SORT命令,在帶有 STORE 引數時產生一個 sortstore事件。如果 STORE 指示的用於儲存排序結果的鍵已經存在,則原鍵會被刪除,因此還會產生一個 del 事件;
SET 以及它的所有變種(SETEX、SETNX和GETSET)都產生set事件。另外,SETEX命令還會產生expire 事件;
MSET 命令,為每個鍵產生一個 set 事件;
SETRANGE 產生一個 setrange 事件;
INCR 、DECR、INCRBY和DECRBY都產生 incrby 事件;
INCRBYFLOAT產生incrbyfloat事件;
APPEND產生append事件;
LPUSH和LPUSHX都產生單個 lpush 事件,即使有多個輸入元素時,也是如此;
RPUSH 和 RPUSHX 都產生單個rpush事件,即使有多個輸入元素時,也是如此;
RPOP 產生 rpop 事件,如果被彈出的元素是列表的最後一個元素,那麼還會產生一個 del 事件;
LPOP 產生 lpop 事件,如果被彈出的元素是列表的最後一個元素,那麼還會產生一個 del 事件;
LINSERT 產生一個 linsert 事件;
LSET 產生一個 lset 事件;
LREM產生一個lrem事件,如果該命令執行之後,列表鍵被清空,則還會產生一個 del 事件;
LTRIM 產生一個ltrim事件,如果該命令執行之後,列表鍵被清空,則還會產生一個 del 事件;
RPOPLPUSH 和 BRPOPLPUSH 產生一個 rpop 事件,以及一個 lpush 事件。兩個命令都保證rpop事件在 lpush 事件之前發出。如果彈出元素之後,列表鍵被清空,則還會產生一個 del 事件;
HSET 、 HSETNX 和 HMSET 都只產生一個 hset 事件;
HINCRBY 產生一個 hincrby 事件;
HINCRBYFLOAT 產生一個 hincrbyfloat 事件;
HDEL 產生一個 hdel 通知。如果執行該命令之後,雜湊鍵被清空,則還會產生一個del事件;
SADD 產生一個 sadd 事件,即使有多個輸入元素時,也是如此;
SREM 產生一個 srem 事件,如果執行該命令之後,集合鍵被清空,則還會產生一個 del 事件;
SMOVE 為源鍵產生一個 srem 事件,併為目標鍵產生一個sadd 事件;
SPOP 產生一個 spop 事件。如果執行該命令之後,集合鍵被清空,則還會產生一個 del 事件;
SINTERSTORE、SUNIONSTORE和SDIFFSTORE分別產生 sinterstore、sunionostore和sdiffstore 三種事件。如果用於儲存結果的鍵已經存在,則還會產生一個 del 事件;
ZINCR產生一個 zincr 事件;
ZADD 產生一個 zadd事件,即使有多個輸入元素時,也是如此;
ZREM 產生一個 zrem 通知,即使有多個輸入元素時,也是如此。如果執行 ZREM 之後,有序集合鍵被清空,則還會產生一個 del 事件;
ZREMEBYSCORE 產生一個 zrembyscore事件,如果用於儲存結果的鍵已經存在,則還會產生一個 del 事件。
ZREMBYRANK 產生一個 zrembyrank事件,如果用於儲存結果的鍵已經存在,則還會產生一個 del 事件。
ZINTERSTORE 和 ZUNIONSTORE 分別產生 zinterstore 和 zunionstore 兩種事件。如果用於儲存結果的鍵已經存在,那麼還會產生一個 del 事件。
每當一個鍵因為過期而被刪除時,產生一個 expired 事件。
每當一個鍵因為 maxmemory策略而被刪除並回收記憶體時,產生一個 evicted 事件。
注意:所有命令都只在鍵真的被改動了之後,才會產生事件通知。比如,當srem命令試圖刪除不存在於集合的元素時,刪除操作執行失敗,因為沒有真正的改動鍵,所以這一操作不會發送通知。
==========================================================
使用maven搭建好springmvc,和搭配好相應的redis的jar包,這個之前的部落格中有,這裡就不提了..
先寫好相應的java處理該訊息通知的類:
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
public class MyRedisKeyExpiredMessageDelegate implements MessageListener {
public void onMessage(Message message, byte[] pattern) {
System.out.println("channel:" + new String(message.getChannel())
+ ",message:" + new String(message.getBody()));
}
}
再在springmvc的xml配置裡面搭配好相應的監聽配置: <bean id="messageListener"
class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="com.zww.common.redis.MyRedisKeyExpiredMessageDelegate" />
</constructor-arg>
</bean>
<bean id="redisContainer"
class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="messageListeners">
<map>
<entry key-ref="messageListener">
<list>
<!-- <bean class="org.springframework.data.redis.listener.ChannelTopic">
<constructor-arg value="[email protected]__:expired" /> </bean> -->
<!-- <bean class="org.springframework.data.redis.listener.PatternTopic">
<constructor-arg value="*" /> </bean> -->
<bean class="org.springframework.data.redis.listener.PatternTopic">
<constructor-arg value="__key*__:expired" />
</bean>
</list>
</entry>
</map>
</property>
</bean>
好了,這個時候可以啟動伺服器,隨便插入一個鍵,設定好過期時間,就會看到列印的日誌了
這裡我在弄的時候有遇到這樣一個坑,就是這個日誌列印了兩次,,仔細一看,是因為springmvc的配置載入了兩次,主要原因還是因為web.xml裡面的配置使springmvc載入兩次,配置好相應的配置就好了....
不過因此也說明了,這個
MyRedisKeyExpiredMessageDelegate
類最好是搞成單列,這樣才能防止通知兩次,使同樣的程式碼執行兩次,出現一些意外的情況,和耗費系統資源
此文參考
http://blog.csdn.net/gqtcgq/article/details/50808729
http://www.bubuko.com/infodetail-1895361.html