Simple Session 源码分析

摘要: 分布式Session的实现有不少,从简单到复杂各类各样,可是要作到分布式Session跟原生本地Session一致的API,对开发人员几乎是0门槛是不容易的。SpringSession 提供了现成的分布式Session功能,本文就是介绍SpringSession的实现细节git

1. 概要redis

本文介绍SpringSession的主要功能的实现原理。在看源码的同时参照SpringSession开了一个“简化”版的Session框架--SimpleSession,简单好用,功能恰好够用,因为删除了不少SpringSession种用不到的功能,源码上可读性更好和自定义开发更容易。spring

2. 替代本地原生Session的秘密session

几乎全部的方案都相似,使用 Filter 把请求拦截掉而后包装 Request 和 Response 使得 Request.getSession 返回的 Session 也是包装过的,改变了原有 Session 的行为,譬如存储属性值是把属性值存储在 **Redis** 中,这样就实现了`分布式Session`了。app

SpringSession 使用 SessionRepositoryFilter 这个过滤器来实现上面所说的。框架

SimpleSession 使用 SimpleSessionFilter 来实现。socket

2.1 SessionRepositoryFilter分布式

包装的类是 SessionRepositoryResponseWrapper 和 SessionRepositoryRequestWrapper 对应 Response和 Request。性能

2.2 SessionRepositoryResponseWrapper测试

继承自 OnCommittedResponseWrapper 主要目标就是一个,当 Response 输出完毕后调用 commit。

2.3 SessionRepositoryRequestWrapper

这个类功能比较多,由于要改变原有不少跟 Session 的接口,譬如 getSession、isRequestedSessionIdValid等。

固然最重要的是 getSession 方法,返回的 Session 是经包装的。

2.3.1 getSession

这里涉及到 Session 和 Repository 下面介绍。

2.3.2 commitSession

因为如今的 Session 跟以前的已经彻底不一样,存储属性值更新属性值都是远程操做,使用"懒操做"模式可使得频繁的操做更加有效率。

这里 onInvalidateSession 和 onNewSession 都是 Strategy 的方法,根据不同的策略采起的处理也不同。

Strategy 有:

  1. CookieHttpSessionStrategy
  2. HeaderHttpSessionStrategy

2.4 Session

SpringSession 的 session 有两部分组成:

  1. Session: 接口, 默认实现类 MapSession , 它是 session 的本地对象,存储着属性及一些特征(如:lastAccessedTime), 最终会被同步到远端, 以及从远端获取下来后存储在本地的实体。
  2. HttpSessionAdapter: 为了能让 Session 跟 HttpSession 接洽起来而设立的适配器。

2.5 Repository

各类实现,最典型用得最多的就是 RedisOperationsSessionRepository, 下面整个第3章(Spring Session Redis存储结构)就是讲整个类存储的策略和设计。

3. Spring Session Redis存储结构

session在存储时分为:

  1. session自己的一些属性存储
  2. 专门负责用于过时的key存储
  3. 以时间为key存储在该时间点须要过时的sessionId列表

3.1 为何须要三个存储结构?

先说明第二存储是用来干吗的,第二存储通常设置成session的过时时间如30分钟或者15分钟,同时session的客户端会注册一个redis的key过时事件的监听,一旦有key过时客户端有会事件响应和处理。

在处理事件时可能会须要该session的信息,这时候第一个存储就有用了,所以第一个存储的过时时间会比第二存储过时时间多1-3min,这就是为何须要把属性存储和过时分开的缘由。

那第三个session的用处呢?对`Redis`比较熟悉的同窗必定会知道其中的奥秘,由于`Redis`的key过时方式是按期随机测试是否过时和获取时测试是否过时(也称懒删除),因为按期随机测试Task的优先级是比较低的,因此即使这个key已通过期可是没有测试到因此不会触发key过时的事件。因此,第三个存储的意义在于,存储了什么时间点会过时的session,这样能够去主动请求来触发懒删除,以此触发过时事件。

3.2 Redis 三个key和存储结构

  1. Session主内容存储,key:spring:session:sessions:{SID},内容:Map,key : value
  2. 过时存储,key:spring:session:sessions:expires:{UUID},内容为空
  3. 过时sessionId列表存储,key:spring:session:expirations:{ExpiryTime},内容Set

3.3 运行方式

由于第二种 key 的存在,因此会自动失效而且发出事件,可是有延迟,因此有个定时任务在不停地扫描当前分钟过时的 key ,即扫描第三种 key ,一旦扫描到就进行删除。

相应事件的程序会把第一种 key 删除。

3.4 代码细节

3.4.1 更新失效时间

3.4.2 Redis事件监听

当 Redis key 过时会往两个频道发布事件,一个是 expired 频道的 key 事件,一个是 key 频道的 expired 事件。(不过须要开启这个功能)

下面是 Spring Session 中 Redis 的事件监听。

container.addMessageListener(messageListener,

Arrays.asList(new PatternTopic("__keyevent@*:del"),

new PatternTopic("__keyevent@*:expired")));

container.addMessageListener(messageListener, Arrays.asList(new PatternTopic(messageListener.getSessionCreatedChannelPrefix() + "*")));

事件处理:

其中,handleCreate、handleDeleted 及 handleExpired 都是用于发布 Spring Context 的本地事件的。

4. Simple Session 简化和优化

4.1 Session存储使用 Map

Session主要内容在Redis中存储采用 Map 结构能够优化读写性能,由于绝大多数属性属于写少读多,若是采用总体作序列化的方式,每次都是整存整取,对于session多个属性操做性能会略快,若是操做属性比较少(如一个)那么性能上会略慢,但总体上讲不会对应用构成瓶颈。

4.2 修改更新

Spring Session 将对session的修改,如建立、销毁以及put属性都作成了在请求最后(Response Commit)再一块儿保存到 Redis,期间随便操做多少次都不会更新到 Redis 中,这样确实减小了对 Redis 的操做,只要是多于一次的都是优化。(也能够设置成每次操做都进行更新)

可是有个问题,若是 response 已经 commit 了,这时候再修改session,值将不会更新到Redis,这个也算不足。

Simple Session 对值的修改也采起懒更新或者当即更新,能够经过配置进行切换。懒更新则使用比 Spring 更简单的方式进行,当 SimpleSessionFilter 执行完毕之后进行提交,而不像 SpringSession 还要考虑 response 输出完再 commit ,因此比较简单,但若是顺序排在前面的 Filter(执行 after 应该在 SimpleSessionFilter 后面)在 chain.doFilter 以后就不能再进行 session 的操做。

4.3 简化存储结构

3 key 式的存储确实是设计巧妙,可是因为 Simple Session 没有去实现 Session 变动(create, delete & expired)事件,因此也就不必去使用 3 key 存储。所以,使用了最简洁的设计: SessionId -> map(key:value),存储 Session 相关属性及 attributes。

4.4 功能删减

Spime Session 实现了主要功能,包括只实现了 Redis 存储方案,至于其余方案如:db,使用者根据须要本身按接口实现。至于如:Spring Security的支持,socket场景的支持,都没有归入主要功能去实现。

5. 代码库

码云:https://gitee.com/alexqdjay/simple-session

相关文章
相关标签/搜索