spring-session源码解读 sesion
2019独角兽企业重金招聘Python工程师标准>>>
spring-session源码解读 sesion 博客分类: java spring
摘要: session通用策略 Session在浏览器通常是通过cookie保存的,cookie里保存了jessionid,代表用户的session id。一个访问路径只有一个session cookie(事实上在客户端就只有一个cookie,jsessionid是作为cookie值的一部分,这里把cookie抽象成类似服务器端的实现),也就是一个访问路径在一个浏览器上只有一个se
session通用策略
Session在浏览器通常是通过cookie保存的,cookie里保存了jessionid,代表用户的session id。一个访问路径只有一个session cookie(事实上在客户端就只有一个cookie,jsessionid是作为cookie值的一部分,这里把cookie抽象成类似服务器端的实现),也就是一个访问路径在一个浏览器上只有一个session,这是绝大多数容器对session的实现。而spring却可以支持单浏览器多用户session。下面就看看spring是怎样去支持多用户session的。
对多用户session的支持
spring session通过增加session alias概念来实现多用户session,每一个用户都映射成一个session alias。当有多个session时,spring会生成“alias1 sessionid1 alias2 sessid2…….”这样的cookie值结构。
spring session提交时如果有新session生成,会触发onNewSession动作生成新的session cookie
public void onNewSession(Session session, HttpServletRequest request, HttpServletResponse response) {Set<String> sessionIdsWritten = getSessionIdsWritten(request);if(sessionIdsWritten.contains(session.getId())) {return;}sessionIdsWritten.add(session.getId());Map<String,String> sessionIds = getSessionIds(request);String sessionAlias = getCurrentSessionAlias(request);sessionIds.put(sessionAlias, session.getId());Cookie sessionCookie = createSessionCookie(request, sessionIds);response.addCookie(sessionCookie);}
a) 确保已经存在cookie里的session不会再被处理。
b) 生成一个包含所有alias的session id的map,并通过这个map构造新的session cookie值。
createSessionCookie会根据一个alias-sessionid的map去构造session cookie。
private Cookie createSessionCookie(HttpServletRequest request,Map<String, String> sessionIds) {//cookieName是"SESSION",spring的session cookie都是//以"SESSION"命名的Cookie sessionCookie = new Cookie(cookieName,"");//省略部分非关键逻辑if(sessionIds.isEmpty()) {sessionCookie.setMaxAge(0);return sessionCookie;}if(sessionIds.size() == 1) {String cookieValue = sessionIds.values().iterator().next();sessionCookie.setValue(cookieValue);return sessionCookie;}StringBuffer buffer = new StringBuffer();for(Map.Entry<String,String> entry : sessionIds.entrySet()) {String alias = entry.getKey();String id = entry.getValue();buffer.append(alias);buffer.append(" ");buffer.append(id);buffer.append(" ");}buffer.deleteCharAt(buffer.length()-1);sessionCookie.setValue(buffer.toString());return sessionCookie;}
a) 当session被invalidate,可能会存在seesionids为空的情况,这种情况下将session cookie的最大失效时间设成立即。
b) 如果只有一个session id,则和普通session cookie一样处理,cookie值就是session id。
c) 如果存在多个session id,则生成前文提到的session cookie值结构。
session cookie的获取
getSessionIds方法会取出request里的session cookie值,并且对每种可能的值结构进行相应的格式化生成一个key-value的map。
public Map<String,String> getSessionIds(HttpServletRequest request) {Cookie session = getCookie(request, cookieName);String sessionCookieValue = session == null ? "" : session.getValue();Map<String,String> result = new LinkedHashMap<String,String>();StringTokenizer tokens = new StringTokenizer(sessionCookieValue, " ");//单用户cookie的情况if(tokens.countTokens() == 1) {result.put(DEFAULT_ALIAS, tokens.nextToken());return result;}while(tokens.hasMoreTokens()) {String alias = tokens.nextToken();if(!tokens.hasMoreTokens()) {break;}String id = tokens.nextToken();result.put(alias, id);}return result;}
- 对单用户session cookie的处理,只取出值,默认为是默认别名(默认为0)用户的session。
- 对多用户,则依据值结构的格式生成alias-sessionid的map。
- 以上两种格式化都是对创建session的逆操作。
getCurrentSessionAlias用来获取当前操作用户。可以通过在request里附加alias信息,从而让spring可以判断是哪个用户在操作。别名是通过”alias name=alias”这样的格式传入的,alias name默认是_s,可以通过setSessionAliasParamName(String)方法修改。我们可以在url上或者表单里添加”_s=your user alias”这样的形式来指明操作用户的别名。如果不指明用户别名,则会认为是默认用户,可以通过setSessionAliasParamName(null)取消别名功能。
public String getCurrentSessionAlias(HttpServletRequest request) {if(sessionParam == null) {return DEFAULT_ALIAS;}String u = request.getParameter(sessionParam);if(u == null) {return DEFAULT_ALIAS;}if(!ALIAS_PATTERN.matcher(u).matches()) {return DEFAULT_ALIAS;}return u;}
触发session提交
spring会通过两个方面确保session提交:
a) response提交,主要包括response的sendRedirect和sendError以及其关联的字节字符流的flush和close方法。
abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper {public OnCommittedResponseWrapper(HttpServletResponse response) {super(response);}/** * Implement the logic for handling the {@link javax.servlet.http.HttpServletResponse} being committed */protected abstract void onResponseCommitted();@Overridepublic final void sendError(int sc) throws IOException {doOnResponseCommitted();super.sendError(sc);}//sendRedirect处理类似sendError@Overridepublic ServletOutputStream getOutputStream() throws IOException {return new SaveContextServletOutputStream(super.getOutputStream());}@Overridepublic PrintWriter getWriter() throws IOException {return new SaveContextPrintWriter(super.getWriter());}private void doOnResponseCommitted() {if(!disableOnCommitted) {onResponseCommitted();disableOnResponseCommitted();} else if(logger.isDebugEnabled()){logger.debug("Skip invoking on");}}private class SaveContextPrintWriter extends PrintWriter {private final PrintWriter delegate;public SaveContextPrintWriter(PrintWriter delegate) {super(delegate);this.delegate = delegate;}public void flush() {doOnResponseCommitted();delegate.flush();}
//close方法与flush方法类似}
//SaveContextServletOutputStream处理同字符流
}
onResponseCommitted的实现由子类SessionRepositoryResponseWrapper提供
private final class SessionRepositoryResponseWrapper extends OnCommittedResponseWrapper {private final SessionRepositoryRequestWrapper request;/** * @param response the response to be wrapped */public SessionRepositoryResponseWrapper(SessionRepositoryRequestWrapper request, HttpServletResponse response) {super(response);if(request == null) {throw new IllegalArgumentException("request cannot be null");}this.request = request;}@Overrideprotected void onResponseCommitted() {request.commitSession();}}
response提交后触发了session提交。
b) SessionRespositoryFilter
仅仅通过response提交时触发session提交并不能完全保证session的提交,有些情况下不会触发response提交,比如对相应资源的访问没有servlet处理,这种情况就需要通过全局filter做保证。
protectedvoiddoFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { try { //省略//filterChain会在所有filter都执行完毕后调用对应的servlet filterChain.doFilter(strategyRequest, strategyResponse); } finally { //所有的处理都完成后提交session wrappedRequest.commitSession() } https://yq.aliyun.com/articles/57421
转载于:https://my.oschina.net/xiaominmin/blog/1598893
spring-session源码解读 sesion相关推荐
- Spring Session - 源码解读
文章目录 Spring Session 流程图 源码分析 Spring Session 流程图 Spring Session 主要是利用过滤器,偷梁换柱,实现session储存无感知的切换. 源码分析 ...
- 【赠书福利】掘金爆火小册同名《Spring Boot源码解读与原理剖析》正式出书了!...
关注我们丨文末赠书 承载着作者的厚望,掘金爆火小册同名读物<Spring Boot源码解读与原理剖析>正式出书! 本书前身是掘金社区销量TOP的小册--<Spring Boot源码解 ...
- 实战:Spring Boot源码解读与原理分析
承载着作者的厚望,掘金爆火小册同名读物<Spring Boot源码解读与原理剖析>正式出书! 本书前身是掘金社区销量TOP的小册--<Spring Boot源码解读与原理剖析> ...
- Spring Session源码解析
AbstractHttpSessionApplicationInitializer,很明显它是一个初始化的类,它是一个抽象类,可以理解为一个公用的基类,然后看一下onStartup这个方法,最主要的方 ...
- Spring:源码解读Spring IOC原理
2019独角兽企业重金招聘Python工程师标准>>> 一.什么是Ioc/DI? IOC容器:主要是完成了 完成对象的创建和依赖的管理注入等. 先从我们自己设计这样一个视角来考虑: ...
- spring beans源码解读之--总结篇
spring beans下面有如下源文件包: org.springframework.beans, 包含了操作java bean的接口和类. org.springframework.beans.ann ...
- spring beans源码解读之 ioc容器之始祖--DefaultListableBeanFactory
spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说, DefaultL ...
- 【转载】Spring @Async 源码解读。
由于工作中经常需要使用到异步操作,一直在使用@Async, 今天抽空学习了一下它的执行原理,刚好看到一篇写的很棒的文章,这里转载过来做个记录,感谢原作者的无私奉献. 原文章链接地址:https://w ...
- spring core源码解读之ASM4用户手册翻译之一asm简介
第一章:ASM介绍 1.1 ASM动机: 程序的分析,生成,转换技术可以应用到许多场景: 1.程序分析,从简单的语法解析到完整的语义分析,可以应用在程序中找到潜在的bug,发现无用的代码,工程代码的逆 ...
最新文章
- 重磅:辽宁副省长获中国版诺贝尔奖 !2020未来科学大奖揭晓
- weiphp----------图灵机器人存在的bug。
- conn.execute参数
- vi插入模式下的backspace键和方向键“不正常”使用解决方法
- 在 WxHtmlWindow 中调用默认浏览器
- 今年怪事特别多 时代盘点09十大奇闻
- oracle 挖掘日志,Oracle 日志挖掘(LogMiner)使用详解
- ASP.NET Core分布式项目实战(Consent Controller Get请求逻辑实现)--学习笔记
- 显示天气 php代码,天气预报查询示例代码
- 六招教你快速提升网站交互体验,降低跳出率
- 拼多多算法笔试2020
- cocos2dx遇到的坑1
- SAP License:第三只眼看财务-现金流量表编制
- Linux下安装JDK说明
- SAP 系统License查看申请及导入
- UCINET软件使用简介 ——主菜单功能简介1
- 服务器更新维护尚未全部完成,【已开服】11月21日全部服务器更新维护公告
- SPSS数据分析-交叉表分析
- VoIP 软电话客户端实例
- Win10关闭自动调节亮度