在上一章讲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的添加和移除都是能够触发事件的。bash
触发的前提是对象实现了HttpSessionBindingListener接口,而后咱们再看下HttpSessionBindingListener的部分
session
里面经过HttpSessionBindingEvent来通知session的attribute变化
数据结构
这一套下来是否是很熟悉,这就是一个典型的监听器模型,也是消息机制的主要表现方式,在spring session经过redis实现分布式的session时,就是经过redis的消息机制来实现标准的session变更通知的,在了解具体的作法先,让咱们先看下redis的消息通知功能。app
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方面的细节,你们能够看这一系列的文章,讲的很好,但看的挺累。