在上一章講spring session存儲到redis的時候,在redis裏面看到每個session存儲都會生成三條記錄,記錄格式以下:html
這就很麻煩了,爲啥不能一一對應,作彼此的天使呢,搞的一對三,很影響風化啊。究竟是道德的淪喪仍是人性的扭曲,讓咱們走進redis,看下具體的數據內容:java
第一個k-v存儲這個Session的id,是一個Set類型的Redis數據結構。這個key中的最後的1570550340000值是一個時間戳,根據這個Session過時時刻滾動至下一分鐘而計算得出。裏面的值是這樣的redis
第二個k-v用來表示Session在Redis中的過時,是個String類型,這個k-v不存儲任何有用數據,只是表示Session過時而設置。這個key在Redis中的過時時間即爲Session的過時時間間隔spring
第三個k-v用來存儲Session的詳細信息,是hash類型,包括Session的建立時間、過時時間間隔、最近的訪問時間、attributes等等。這個k的過時時間爲Session的最大過時時間 + 5分鐘。若是默認的最大過時時間爲30分鐘,則這個k的過時時間爲35分鐘數據庫
說到這裏,會有個靈魂的拷問,就一個session的存儲,爲啥要搞三條記錄?這裏要提一下HttpSession的接口規範了。緩存
session雖然也是一條數據,可是和普通的數據仍是有不一樣的,咱們去查httpsession的javadoc能夠看到,session的添加和移除都是能夠觸發事件的。session
觸發的前提是對象實現了HttpSessionBindingListener接口,而後咱們再看下HttpSessionBindingListener的部分
數據結構
裏面經過HttpSessionBindingEvent來通知session的attribute變化
app
這一套下來是否是很熟悉,這就是一個典型的監聽器模型,也是消息機制的主要表現方式,在spring session經過redis實現分佈式的session時,就是經過redis的消息機制來實現標準的session變更通知的,在瞭解具體的作法先,讓咱們先看下redis的消息通知功能。分佈式
Redis從2.8.0版本後,推出 Keyspace Notifications 特性。Keyspace Notifications 容許客戶端能夠以 訂閱/發佈(Sub/Pub)模式,接收那些對數據庫中的鍵和值有影響的操做事件。這些操做事件具體來講,就是 del , expire , set , rpop等啦。
redis默認不會開啓keyspace notifications,由於開啓後會對cpu有消耗,因此開啓須要額外配置redis.conf文件
############################# EVENT NOTIFICATION ############################## # 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 Ex # # 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 "Ex"
關鍵就是最下一句,Ex的意思能夠看上面的註釋。啓動後只要咱們訂閱一個特定的channel,該channel下面的數據變化咱們就能收到通知了。
改好配置,重啓redis,就可以開啓消息通知了。
Redis中帶有過時的key有兩種方式:
問題時訪問時發現過時可能會在好久之後,因此怎麼才能在key過時的時候就知道呢?
spring-session中有個定時任務,每一個整分鐘都會查詢相應的spring:session:expirations:整分鐘的時間戳中的過時SessionId,而後再訪問一次這個sessionId,即spring:session:sessions:expires:SessionId,以便可以讓Redis及時的產生key過時事件——即Session過時事件。而這個定時任務的時間時能夠配置的,配置的參數就時上一章結尾說的cleanupCron
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware, SchedulingConfigurer { static final String DEFAULT_CLEANUP_CRON = "0 * * * * *"; private String cleanupCron = DEFAULT_CLEANUP_CRON;
默認就是一分鐘清理一次過時的緩存,能夠根據本身的需求作更改。
我這裏其實講的不是很詳細,關於spring session方面的細節,你們能夠看這一系列的文章,講的很好,但看的挺累。