分布式cookie-session的实现(spring-session)
分布式cookie-session的实现(spring-session)
本文使用的spring-session版本为 1.0.0,地址为: https://github.com/spring-projects/spring-session
1 session存储策略
存储,即在后台使用session的setAttribute,getAttribute等方法时,这些内部存放的数据最终存储至什么位置。比如在默认的tomcat实现中,相应的数据即存储在内存中,并在停止之后会序列化至磁盘中。
可以使用内存存储和第三方存储,如redis。对于集群式的session存储,那么肯定会使用第三方存储的实现。
在spring-session中,对session存储单独作了一个定义,但定义上基本保证与http session一致,主要的目的在于它可以支持在非http的环境中模拟使用。因此不直接使用http session接口。
先看定义:
|
1
2
3
4
5
6
7
8
|
public interface Session { /** 获取惟一的id,可以理解为即将每个session当作一个实体对象 */ String getId(); <T> T getAttribute(String attributeName); Set<String> getAttributeNames(); void setAttribute(String attributeName, Object attributeValue); void removeAttribute(String attributeName);} |
从这个定义来看,如果要使用httpSession,如果实现了这个session接口,那么实现上就可以全部实现httpSession对于存储的要求。对于非httpSession场景,使用这个也可以达到session存储的目的。
当然,为了保证在会话场景中会使用到失效,最后访问时间,最大不活跃时间的目的,spring-session也有一个继承于session接口的expiringSession接口。
1.0 id主键的生成
对于id,即理解为session实体对象惟一键,可以采用任意的一种惟一key生成策略。比如,使用uuid来生成惟一键。同时,也可以将这个id认为就是在http中sessionCookie的值
1.1 map存储
如果是map来存储,那么 set,get,remove就可以直接使用map的相应实现即可。在spring-session实现中MapSession,即采用内部的一个hashmap来进行存储。
1.2 redis存储
在sprng-session中,将属性的存储和整体的存储分开,使用专门的仓库来处理session实体的处理。对于从领域模型的概念来说,set,get,removeAttribute只是对属性的处理,处理的是一个内部状态的变化,对于整体的实体来说,并没有整体上的处理。具体到实现,在redis的存储实现中,spring-session内部使用了一个 mapSession来存储相应的属性信息。
在一个实体被创建之后,相应的属性信息被全部设置至mapSession中,然后接下来的属性访问均通过mapSession来处理。为了最终存储相应的数据值,redis实现使用了一个额外的deltaMap来存放变化了的数据,并在重新保存时,一次性地将所有属性put至redis中。
从这个实现来看,spring-session的实现并不是实时地与redis进行交互,这种实现方式在解决同一session设置冲突属性时可能存在问题。因此存在这种场景的,需要重新实现相应的逻辑。
2 session仓库策略
之所以将存储策略和仓库策略分开,也是spring-session的一个设计思想。spring将session设计为一个实体,因此将实体对象的操作和属性的操作进行拆分。在前面的存储策略已经描述了属性的操作,因此这里的仓库策略主要处理实体的创建,获取,更新,删除等,即CRUD。如下的定义所示:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public interface SessionRepository<S extends Session> { /** 新建 */ S createSession(); /** 保存或更新 */ void save(S session); /** 获取 */ S getSession(String id); /** 删除 */ void delete(String id);} |
2.1 本地仓库
如果是本地仓库,那么可以使用一个本地全局的globalMap,然后使用sessionId作为key,mapSession作为value来实现即可。
2.2 redis仓库
如果是resi仓库,那么在新建时,只是在本地创建一个redisSession对象,然后在redis存储中使用一个 hash结构来进行存储。即<I,<K,V>>的结构。其中I即表示sessionId,<k,V>表示具体的redisSession对象。其中getSession,delete都是针对I的操作,而save则在在指定I的情况下,直接保持<K,V>即可。
为了在一定程度上进行优化,以及解决在一定程序上的覆盖问题,在redis实现时。spring-session只对修改过的属性作存储,即当使用setAttribute处理属性时,spring-session使用额外的delta来保存修改过的属性,最后进行save时,只操作这部分数据即可。并且redis也支持调用hSet来保存或更新修改过的数据。
3 session传输策略
3.1 cookie传输
常规的实现也是使用cookie传输,比如tomcat,jetty等。在这种情况下,后端在创建session时,如果这是新的session,会自动调用原生response.addCookie以创建一个新的cookie信息。为保证安全,采用httpOnly进行创建。在发送给客户端之后的每次交互,浏览器会自动将这些信息传输至服务器端。然后服务器端直接从cookie中获取到sessionId,再进一步操作即可。
对于这种实现,应用程序开发不需要作任何的调整,浏览器会自动处理cookie的传输。
3.2 header传输
header传输,即在创建新session时,往response header中使用addHeader添加一个新的响应头,如session头,headerValue中存放相应的sessionId值。
在客户端实现中,客户端代码需要手动地将响应值进行记录,并在请求时加入到请求头当中。并且需要监听响应头值的变化,比如sessionId值的变化处理。相比cookie传输来说,这种实现对于开发更复杂一点。
4 http协议兼容
4.1 为保证http协议兼容,在session信息准备好之后,其必须在响应头之后进行处理
不管是使用cookie传输还是header传输,在响应时都需要保证在响应body输出时,相应的头信息都应该先被处理。(cookie也是一种特殊的header)。如果像以下的代码,就不能保证session响应被正确地处理
|
1
2
3
4
|
X implements Filter { filterChain.doFilter(request,response) // do session logic} |
在这种实现中,如果在应用代码中直接使用response的outputStream进行输出时,这里的过滤器实现中的do Session操作就不能实现相应的逻辑。因为http协议中的消息机制已经不再允许再输出body之后输出header信息了。
在spring-session的实现中,我们只需要保证在调用response处理响应body时,能够处理session逻辑即可。那么可以使用一种hack的技术,针对在response输出时,判定是否在处理body或应该结束响应时,加入特定的hack以处理我们的do session操作。因此提供了 OnCommittedResponseWrapper 以便在特定的时机进行处理,在具体的 onResponseCommitted中,处理session的delete响应和save等即可。
4.2 为支持多浏览器访问,因此在特定的路径信息处理时,应当自动地处理相应的browser参数
关于多browser支持,可以先看看此篇文章。
http://docs.spring.io/spring-session/docs/current/reference/html5/#httpsession-multi
在多browser支持时,主要即在请求参数中增加相应的浏览器识别参数_s,那么在需要进行界面跳转或其它地址处理时,后台应该能够自动地处理相应的参数信息。在spring-session中,为了对应用程序透明,通过重写response的encodeURL和encodeRedirectURL时,增加对相应_s的处理即达到相应的处理透明即可。
转载请标明出处:i flym
本文地址:http://www.iflym.com/index.php/code/201503170001.html
分布式cookie-session的实现(spring-session)的更多相关文章
- Spring Session实现分布式session的简单示例
前面有用 tomcat-redis-session-manager来实现分布式session管理,但是它有一定的局限性,主要是跟tomcat绑定太紧了,这里改成用Spring Session来管理分布 ...
- 使用Spring Session实现Spring Boot水平扩展
小编说:本文使用Spring Session实现了Spring Boot水平扩展,每个Spring Boot应用与其他水平扩展的Spring Boot一样,都能处理用户请求.如果宕机,Nginx会将请 ...
- Re:从零开始的Spring Session(一)
Session和Cookie这两个概念,在学习java web开发之初,大多数人就已经接触过了.最近在研究跨域单点登录的实现时,发现对于Session和Cookie的了解,并不是很深入,所以打算写两篇 ...
- 通过Spring Session实现新一代的Session管理
长期以来,session管理就是企业级Java中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原生云应 ...
- 转:通过Spring Session实现新一代的Session管理
长期以来,session管理就是企业级Java中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原生云应 ...
- 大话 Spring Session 共享
javaweb中我们项目稍微正规点,都会用到单点登录这个技术.实现它的方法各家有各界的看法.这几天由于公司项目需求正在研究.下面整理一下最近整理的心得. 简介 在分布式项目中另我们头疼的是多项目之间的 ...
- Spring Session工作原理
本文首发于 vivo互联网技术 微信公众号 https://mp.weixin.qq.com/s/KCOFv0nRuymkX79-RZi9eg 作者:张正林 目录:1.引入背景2.使用方法3.工作流程 ...
- 通过 Spring Session 实现新一代的 Session 管理
长期以来,session 管理就是企业级 Java 中的一部分,以致于我们潜意识就认为它是已经解决的问题,在最近的记忆中,我们没有看到这个领域有很大的革新. 但是,现代的趋势是微服务以及可水平扩展的原 ...
- 实战开发,使用 Spring Session 与 Spring security 完成网站登录改造!!
上次小黑在文章中介绍了四种分布式一致性 Session 的实现方式,在这四种中最常用的就是后端集中存储方案,这样即使 web 应用重启或者扩容,Session 都没有丢失的风险. 今天我们就使用这种方 ...
- spring session 和 spring security整合
背景: 我要做的系统前面放置zuul. 使用自己公司提供的单点登录服务.后面的业务应用也是spring boot支撑的rest服务. 目标: 使用spring security管理权限包括权限.用户请 ...
随机推荐
- mysql 查询 字段的类型
select column_name,data_type from information_schema.columnswhere table_name = '表名'
- 1058FBI<二叉树,递归,后序遍历>
问题描述 我们可以把由"0"和"1"组成的字符串分为三类:全"0"串称为B串,全"1"串称为I串,既含"0&q ...
- 开发板S3C2440挂起NFS步骤
第一.安装.配置.启动FTP.SSH或NFS服务 参考韦东山的嵌入式linux应用开发完全手册 http://pan.baidu.com/s/1o79h3n0 第二.windows.linux以及开发 ...
- HDU 4287 Intelligent IME(字典树)
在我没用hash之前,一直TLE,字符串处理时间过长,用了hash之后一直CE,(请看下图)我自从经历我的字典树G++MLE,C++AC以后,一直天真的用C++,后来的CE就是因为这个,G++才支持这 ...
- HDU 1527 取石子游戏(威佐夫博弈)
基础威佐夫博弈,判断奇异局势即可,判断方式为k为两数之差绝对值,(sqrt(5) + 1) / 2 * k若等于两数小者则为奇异局势,也就是必败态. #include<stdio.h> # ...
- java中创建多线程的方式
在java中比较常用的有三种创建多线程的方式. 方式一:继承Thread类,要重写run方法. 在MyThread类 public class MyThread extends Thread { @O ...
- 基于POI的Excel导入导出(JAVA实现)
今天做了个excel的导入导出功能,在这记录下. 首先现在相关poi的相关jar包,资源链接:http://download.csdn.net/detail/opening_world/9663247 ...
- ScreenCaptureHtmlUnitDriver.java
https://github.com/apache/incubator-zeppelin/blob/master/zeppelin-server/src/test/java/com/webautoma ...
- nodejs连接mysql实例
1.在工程目录下运行npm install mysql安装用于nodejs的mysql模块: 2.创建db.js模块用于连接mysql,同时定义query查询方法: var mysql = requi ...
- ZenCoding 个人理解和总结
我的理解:ZenCoding是一个html简写的语法,可以最快速的生成html. 不少IDE应该都支持,我用的intellij idea是支持的. ZenCoding表示和CSS/JS有相通之处,比如 ...