28 关于SpringSession的永不失效

2024-05-28 15:38
文章标签 失效 28 永不 springsession

本文主要是介绍28 关于SpringSession的永不失效,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前的时候, 有一个需求, 需要用户的 session 一直存在, 此session里面记录了一些 用户的一些业务数据, 需要 在关闭了浏览器之后, session中的数据, 依然 存在

环境 : SpringSession 来托管session, 采用 redis 来存储session, 以下代码基于 spring-session - 1.2.0.RELEASE

----- 手动分割线 -----

然后 对于这个问题, 我想的 就是直接 session.setMaxInactiveInterval(-1), 直接 让session永不过期不就解决了吗, 但是 同事按照这种思路 实现了一下, 结果 发现 还是关闭了浏览器之后, session 就"消失"了然后 上周的时候, ??, 周二吧, 好像是, 然后 跟了一下代码, 瞅了瞅, 看了一下 HttpSession.setMaxInactiveInterval, 以及我们这里的 委托给的 ExpiringSession. setMaxInactiveIntervalInSeconds 的注释, 上面也是很明晰的写了, "A negative time indicates that the session will never timeout.", 我特么 就在想 为什么没有生效呢??上周二的时候, 浏览器里面看 SESSION 对应的 expire/Max-Age 是 session, 因此 关闭了浏览器之后, sessionId 对应的 cookie 就失效了m, 然后导致了 session 的"消失", 然后 SpringSession 重新创建了一个 session, 这就造成了我们现在的情况

----- 手动分割线 -----

然后 本来就是想, 那天晚上空了的时候, 看一看, 谁知道 最近妈的, 都太忙了, 加班加班加班, 然后 只好留到了周末然后 昨天的时候, 又有一些朋友的其他的事情, 然后 只好留到了今天, 然后 今天下午的时候, 又重新溜了一下 SessionRepositoryFilter 的这部分的代码然后 忽略SpringSession管理session的部分的细节, 我们这里 直奔关于我们这里的这个问题的相关部分, 为什么 sessionId 对应的 cookie 的生命周期不为很长的一个时间, 而是默认的关闭浏览器就失效呢?定位到 SessionRepositoryRequestWrapper. commitSession, 这个方法, 这个方法调用的地方是, SessionRepositoryResponseWrapper. onResponseCommitted, SessionRepositoryFilter.doFilterInternal也就是在 Response 写出数据的时候, 以及SessionRepositoryFilter 以及之后的Filter 以及XXXServlet处理完了之后的时候 调用了一下 commitSessionSessionRepositoryFilter.doFilterInternal

	@Overrideprotected void doFilterInternal(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response, this.servletContext);SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest, response);HttpServletRequest strategyRequest = this.httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);HttpServletResponse strategyResponse = this.httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);try {filterChain.doFilter(strategyRequest, strategyResponse);}finally {wrappedRequest.commitSession();}}




SpringSession 管理 session 的逻辑, 就在于 SpringSession 重写的几个 Wrapper, RequestWrapper, ResponseWrapper, SessionWrapper
这里 差不多就是创建了 Wrapper, 然后把逻辑留给之后的 Filter, 以及处理业务的Servlet, 然后 责任链回到了当前 Filter, 之后 commitSession


SessionRepositoryRequestWrapper. commitSession
		private void commitSession() {HttpSessionWrapper wrappedSession = getCurrentSession();if (wrappedSession == null) {if (isInvalidateClientSession()) {SessionRepositoryFilter.this.httpSessionStrategy.onInvalidateSession(this, this.response);}}else {S session = wrappedSession.getSession();SessionRepositoryFilter.this.sessionRepository.save(session);if (!isRequestedSessionIdValid()|| !session.getId().equals(getRequestedSessionId())) {SessionRepositoryFilter.this.httpSessionStrategy.onNewSession(session,this, this.response);}}}




这里 我们着重需要关注的是, 这里 SessionRepositoryFilter.this.httpSessionStrategy.onNewSession
this.sessionRepository.save(session) 这里, 持久化当前 session, 如果 Servlet 处理的过程中, 对于Session有一些处理, 这里外层统一处理一下, 持久化变更的数据[如果配置了 RedisHttpSessionConfiguration.flushMode为IMMEDIATE, 此配置会传到 RedisHttpSessionConfiguration. sessionRepository, 创建的 RedisOperationsSessionRepository, 然后这样, 创建的session, 每次有更新之后, 都会直接持久化到 redis中]
在客户端访问服务器第一次生成 session 的时候, 会处理一些业务, 放在这里onNewSession 


我们这里看看默认的 CookieHttpSessionStrategy 的实现
CookieHttpSessionStrategy. onNewSession
	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());String cookieValue = createSessionCookieValue(sessionIds);this.cookieSerializer.writeCookieValue(new CookieValue(request, response, cookieValue));}


添加 sessionKey -> sessionId, 到sessionId的集合中, 然后 通过response写出到 cookie中, 然后 这里面就是 我们要关注的重点了, 也就是 为什么我们这里的 sessionId 对应的 cookie 关闭了浏览器就失效的原因了


DefaultCookieSerializer. writeCookieValue
	public void writeCookieValue(CookieValue cookieValue) {HttpServletRequest request = cookieValue.getRequest();HttpServletResponse response = cookieValue.getResponse();String requestedCookieValue = cookieValue.getCookieValue();String actualCookieValue = this.jvmRoute == null ? requestedCookieValue: requestedCookieValue + this.jvmRoute;Cookie sessionCookie = new Cookie(this.cookieName, actualCookieValue);sessionCookie.setSecure(isSecureCookie(request));sessionCookie.setPath(getCookiePath(request));String domainName = getDomainName(request);if (domainName != null) {sessionCookie.setDomain(domainName);}if (this.useHttpOnlyCookie) {sessionCookie.setHttpOnly(true);}if ("".equals(requestedCookieValue)) {sessionCookie.setMaxAge(0);}else {sessionCookie.setMaxAge(this.cookieMaxAge);}response.addCookie(sessionCookie);}


新建 cookie, 配置path, domain, 等等参数信息
配置 maxAge, 这里"sessionCookie.setMaxAge(this.cookieMaxAge);", 默认的 DefaultCookieStrategy. cookieMaxAge 为-1, 浏览器这边对应的就是关闭窗口 cookie 失效
然后 这里, 如果我们需要 自定义 cookie的声明周期的话, 需要 自己创建 CookieSerializer, 然后 配置下cookieMaxAge, 然后 吧刚才定义的 CookieSerializer 配置到 XXXHttpSessionConfiguration, 里面就可以了


完, 不过 溜了一圈, 里面 还是有一些疑惑的地方
spring - session- expirations : $timeoutTs [$timeoutTs + 300] [expires:$sessionId, ]- sessions- session : $sessionId [$timeoutTs + 300] { maxInactiveInterval : xx, lastAccessedTime : xx, creationTime : xx }- expires- $sessionId [$timeoutTs] { }


1. spring:session:sessions:expires 这一层的作用是什么??, 标记当前 有哪些存活的 session 吗 ?
2. spring:session:sessions:session:$sessionId 这一层为什么要让他多存活5分钟??, 
3. RedisOperationsSessionRepository. leanupExpiredSessions(), 这个定时任务存在的意义是什么?? 
留几个问题, 之后的时候, 再回来看看, 再来补充补充吧??




这篇关于28 关于SpringSession的永不失效的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1010986

相关文章

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Idea插件MybatisX失效的问题解决

《Idea插件MybatisX失效的问题解决》:本文主要介绍Idea插件MybatisX失效的问题解决,详细的介绍了4种问题的解决方法,具有一定的参考价值,感兴趣的可以了解一下... 目录一、重启idea或者卸载重装MyBATis插件(无需多言)二、检查.XML文件与.Java(该文件后缀Idea可能会隐藏

C++迭代器失效的避坑指南

《C++迭代器失效的避坑指南》在C++中,迭代器(iterator)是一种类似指针的对象,用于遍历STL容器(如vector、list、map等),迭代器失效是指在对容器进行某些操作后... 目录1. 什么是迭代器失效?2. 哪些操作会导致迭代器失效?2.1 vector 的插入操作(push_back,

MySQL索引失效问题及解决方案

《MySQL索引失效问题及解决方案》:本文主要介绍MySQL索引失效问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql索引失效一、概要二、常见的导致MpythonySQL索引失效的原因三、如何诊断MySQL索引失效四、如何解决MySQL索引失

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处

MySQL进阶之路索引失效的11种情况详析

《MySQL进阶之路索引失效的11种情况详析》:本文主要介绍MySQL查询优化中的11种常见情况,包括索引的使用和优化策略,通过这些策略,开发者可以显著提升查询性能,需要的朋友可以参考下... 目录前言图示1. 使用不等式操作符(!=, <, >)2. 使用 OR 连接多个条件3. 对索引字段进行计算操作4

Goland debug失效详细解决步骤(合集)

《Golanddebug失效详细解决步骤(合集)》今天用Goland开发时,打断点,以debug方式运行,发现程序并没有断住,程序跳过了断点,直接运行结束,网上搜寻了大量文章,最后得以解决,特此在这... 目录Bug:Goland debug失效详细解决步骤【合集】情况一:Go或Goland架构不对情况二:

mysql外键创建不成功/失效如何处理

《mysql外键创建不成功/失效如何处理》文章介绍了在MySQL5.5.40版本中,创建带有外键约束的`stu`和`grade`表时遇到的问题,发现`grade`表的`id`字段没有随着`studen... 当前mysql版本:SELECT VERSION();结果为:5.5.40。在复习mysql外键约

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

oracle数据库索引失效的问题及解决

《oracle数据库索引失效的问题及解决》本文总结了在Oracle数据库中索引失效的一些常见场景,包括使用isnull、isnotnull、!=、、、函数处理、like前置%查询以及范围索引和等值索引... 目录oracle数据库索引失效问题场景环境索引失效情况及验证结论一结论二结论三结论四结论五总结ora