SpringSession深入浅出(一)

2023-11-11 04:40

本文主要是介绍SpringSession深入浅出(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、session来由

要谈session,一定是要说到用它带场景http协议。http协议是无状态协议,就像鱼的记忆,即使是同一浏览器给客户端给同一个服务器再来请求,已经记不起来你是谁。在互联网早期,承载网页大部分都是静态简单的信息单向传递,用户打开新闻网页浏览、结束等是一种简单的交互方式。复杂场景下, 业务是复杂的,承载业务系统和用户之间有非常频繁的交互,一个操作可能涉及到多个请求,必须让http服务器记住你是谁。于是就有了cookie和session。

cookie和session都能针对请求中的特殊值进行存储,适合于标识多次请求之间公用的内容存储和传递。但要知道区别,合理使用:

  • 存储位置:cookie存储在客户端(如浏览器等);session存储在服务器端。

  • 空间限制:cookie由于所有访问网站都会使用客户端的公用空间,针对单条cookie的value大小和cookie总的条数都是有限制的,超出部分根据不同客户端策略会有不同的处理。例如某个泛域名由于cookie的个数很多,造成存储用户信息的cookie经常被逐出,导致用户频繁登录。session的存储一般更加灵活,一般借助于更“专业”的存储,比如普通的RDB、高速缓存Redis等。

  • 安全区别:cookie由于存储在客户端不够安全,在存储和传输的时候经过的环境比较复杂,可能会被截获、篡改、伪造等,一般存储需要进行加密、签名、防枚举。session存储在服务器端相对安全,可以存储的用户标识,角色、权限等相关信息公用基础信息。

  • 性能区别:cookie存储在本地,可以将信息冗余到本地,减少远程调用耗时,可以考虑将常用非敏感数据进行存储减少系统负担,提高性能。session存储在远程服务端,读取、传输都会消耗资源、耗时增加。

二、打算怎么设计

如果由你来设计一个session的实现框架怎么实现呢?要有哪些数据模型、关键业务动作

由于session需要进行持久化,我们如果简化思考,我们只存储在关系型数据库RDB,应该怎么设计表呢?

应该设置两张表,一个表存储基础的session信息,另外一个表存储session对应的其他信息

  • session基本信息表

字段名

字段说明

类型

备注

session_id

唯一ID

varchar

create_time

创建时间

datetime

update_time

更新时间

datetime

expire_time

失效时间

bigint

status

状态

varchar

  • session存储值表

字段名

字段说明

类型

备注

session_id

session的唯一ID

varchar

attribute_name

存储值的Key值

varchar

atrrbutie_value

存储的Value值

varchar

以上就是我们针对一个session的非常简单的初始设计思路。没错,spring-session也是以此为核心进行展开设计的。

三、spring-session代码结构

spring-session是spring家族中针对session的系列服务模块,不需要依赖于web容器,支持集群情况下的会话管理。

  • 支持替换应用Tomcat中的HttpSession

  • 接受webSocket消息使HttpS额生死哦你保持状态

  • 与应用容器无关的方式替换spring webflux

  • 提供和spring-security的更方便的集成

spring-session的代码部分包括:

  • spring-core:用于定义主要的接口、模型、事件、注解、基础配置模型

  • spring-session-data-mongodb:mongodb实现的session存储管理

  • spring-session-data-redis:利用redis实现的session管理

  • spring-session-jdbc:实现了利用关系型数据来实现的session存储管理

  • spring-session-hazelcast:演示了javaEE应用程序中如何与Hazelcast结合使用

      对比从我们自己的设计,来和spring-session比较一下,看看spring-session从设计的角度是如何一步步演进。

      Session模型设计,总体和我们之前设计的出入不大:

  • SessionRepository:Session的管理进行抽象,定义了session的新建、查找、删除的基本功能;

  • FindByIndexNameSessionRepository:为什么会扩展一个IndexName的Repository呢?提供了一种查找具有给定索引名称和索引值的所有会话的方法。作为所有提供的FindByIndexNameSessionRepository实现都支持的常见用例,有一种便捷的方法可以为特定用户查找所有会话。通过确保使用用户名填充名称.

  • ReactiveSessionRepository:这个用于非阻塞和反应式进行操作session。

  • HazelcastIndexSessionRepository:Hazecast实现

  • RedisIndexSessionRepository:高速缓存Redis的实现,存储调用spring-data-redis进行redis操作

  • MongoIndexSessionRepository:Mango数据库实现,存储调用spring-data-mongodb进行操作

  • JDBCIndexSessionRepository:RDB关系型数据库实现,支持几种主流的数据库实现Orcal、db2、mysql、SQLServer、PostgreSql。

四、产品架构

五、重点介绍几个技术点

1、如何和SpringSession集成

SessionRepositoryFilter:

SpringSession通过继承OncePerRequestFilter进行,spring框架的针对rpc请求的责任链注册进去的。filter的order需要保证考前执行。

DEFAULT_ORDER = Integer.MIN_VALUE + 50;

在链路中做了三件事情,

  • requst增强为SessionRepositoryRequestWrapper,主要增加的功能为:

    • 重写session操作

      • 提交:commitSession

      • 更新:setCurrentSession

      • 查找:getSession

      • 其他:

        • chanageSessionId:防止黑客拿到sessionID,进行身份冒充。通过change方式通知相关方刷新sessionId

  • response增强

  • 提交session

但是为什么要继承OncePerRequestFilter呢?直接注册普通的Filter行不行?

OncePerRequestFilter

OncePerRequestFilter,这个的作用是确保filter只执行一次,这个filter虽然长的和spring-web的一样,但这个是springweb框架的简化版,确保每个请求只执行一次。

/** * Allows for easily ensuring that a request is only invoked once per request. This is a * simplified version of spring-web's OncePerRequestFilter and copied to reduce the foot * print required to use the session support. * * @author Rob Winch * @since 1.0 */

关于spring-web中OncePerRequestFilter。

Filter base class that aims to guarantee a single execution per request dispatch, on any servlet container. It provides a doFilterInternal method with HttpServletRequest and HttpServletResponse arguments. As of Servlet 3.0, a filter may be invoked as part of a REQUEST or ASYNC dispatches that occur in separate threads. A filter can be configured in web.xml whether it should be involved in async dispatches. However, in some cases servlet containers assume different default configuration. Therefore sub-classes can override the method shouldNotFilterAsyncDispatch() to declare statically if they should indeed be invoked, once, during both types of dispatches in order to provide thread initialization, logging, security, and so on. This mechanism complements and does not replace the need to configure a filter in web.xml with dispatcher types. Subclasses may use isAsyncDispatch(HttpServletRequest) to determine when a filter is invoked as part of an async dispatch, and use isAsyncStarted(HttpServletRequest) to determine when the request has been placed in async mode and therefore the current dispatch won't be the last one for the given request. Yet another dispatch type that also occurs in its own thread is ERROR. Subclasses can override shouldNotFilterErrorDispatch() if they wish to declare statically if they should be invoked once during error dispatches. The getAlreadyFilteredAttributeName method determines how to identify that a request is already filtered. The default implementation is based on the configured name of the concrete filter instance. Since: 06.12.2003 Author: Juergen Hoeller, Rossen Stoyanchev

3、Redis实现

利用redis实现session的存储方式,使用模式比较常用,这里重点关注一下

redis存储sessionKey的设计

发起一条http请求到spring框架,这个时候框架会写入session信息,举例:

  HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 maxInactiveInterval 1800 lastAccessedTime 1404360000000 sessionAttr:attrName someAttrValue sessionAttr:attrName2 someAttrValue2EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32feEXPIRE spring:session:expirations1439245080000 2100

意味着:

  1. 创建了一条33fdd1b6-b496-4b33-9f7d-df96679d32fe的session
  2. 这个session的创建时间为1404360000000(从19701.1年开始)
  3. 这个session有两个属性attrName,attrName2;

redis的几个关键Key:

  • spring:session:sessions:
    • 用于存储每一个session的内的各种属性
    • 过期时间为都会+5分钟,便于在过期后还能访问到session的相关内容。

You will note that the expiration that is set is 5 minutes after the session actually expires. This is necessary so that the value of the session can be accessed when the session expires. An expiration is set on the session itself five minutes after it actually expires to ensure it is cleaned up, but only after we perform any necessary processing.

  • findById:会针对获取的session进行有效期判定,如果过期默认不返回(接口参数开关可以设置是否返回过期session)
  • spring:session:sessions:expires
  • 用来存储一个Key对应的空的缓存
  • 在过期的时候,会产生过期事件,但是无法保证key的过期时间抵达后立即生成过期事件。spring-session为了能够及时的产生Session的过期时的过期事件
  • spring:session:expirations
  • 过期key的一个“筒”,每分钟生成一个,将这一分钟之内生成新的sessionId全部放在这个里面。
  • spring-session中有个定时任务,每个整分钟都会查询相应的spring:session:expirations:整分钟的时间戳中的过期SessionId,然后再访问一次这个SessionId,即spring:session:sessions:expires:SessionId,不做删除只查询一次,触发redis删除cookie,以便能够让Redis及时的产生key过期事件

事件:

springSession提供针对session生命周期的扩展点,用户可针对session的变化定义上层业务行为。通过spring-data-redis的RedisMessageListenerContainer进行事件监听。事件包括:

  • SessionCreatedEvent:创建session时的事件
    • "spring:session:channel:created:${sessionId}"发送redis事件,服务器集群内机器将收到SessionCreatedEvent事件
  • SessionDestroyedEvent:通过destroy方法产生的事件
  • SessionDeletedEvent:通过删除产生的事件
  • SessionExpiredEvent:session过期产生事件

上述事件,在一些长连接,例如:Spring Session's WebSocket场景中,可以通过在session过期的时候及时关闭连接。更多redis事件信息看这里。

如何关闭事件

ConfigureNotifyKeyspaceEventsAction用于注册redis的事件中,集成于ConfigureRedisAction。如果要关闭事件机制,需要实现固定ConfigureRedisAction设置这个Bean为NO_OP就可以

@Beanpublic static ConfigureRedisAction configureRedisAction() {return ConfigureRedisAction.NO_OP;}

XML定义Bean

<util:constantstatic-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>

4、更详细的技术点介绍

六、其他

1、session和Tomcat

StandardSession来定义的session主要模型,通过实现Session、Serializable、HttpSession等几个接口,通过外观模式,封装session的基础服务。

spring的attribute存在ConcurrentHashMap中

/** * The collection of user data attributes associated with this Session. */protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();

tomcat是如何做session 同步的? 如果不是单体应用,一个应用在集群的多台机器中,如果session各自独立,就无法实现,这个时候就需要进行会话保持。会话保持有几种方式:

负载均衡会话保持

  • 简单会话保持:根据访问请求的源地址作为判断关连会话的依据,对来自同一IP地址的所有访问请求在作负载均时都会被保持到一台服务器上去。

  • cookie模式:将会话标识在后端服务器中间进行读取、插入;

  • SSL sessionId模式:SSL环境中,在建立SSL中插入SSL SessionID信息进行会话保持

关键服务模型

DeltaSession

主要目的是用于集群间同部的session模型,除了实现上述的StandardSession之外,还实现了Externalizable、ClusterSession、ReplicatedMapEntry三个接口,特别实现了集群间同步服务、比较服务等。

一个请求作为一个完整颗粒度,修改属性的操作会放在指定的队列中,然后将其同步到集群其他节点,节点一次执行本次针对会话属性的操作。

​​​​​​​

StandardManager

标准的实现session的服务,提供一个专门管理某个web应用所有会话的容器,并且会在web应用启动停止时刻进行会话重加载和持久化。例如会话id生成、根据会话id找出对应的会话、对于过期的会话进行销毁等等操作。

DeltaManager

DeltaManager会话管理器是tomcat默认的集群会话管理器,它主要用于集群中各个节点之间会话状态的同步维护。会话同步通信解决方案,写入完成后才会相应客户端。为区分不同的动作必须要先定义好各种事件,例如会话创建事件、会话访问事件、会话失效事件、获取所有会话事件、会话增量事件、会话ID改变事件等等,实际上tomcat集群会有9种事件

PersistentManager

用于存储session的管理服务,实现各种会话存储方式。作为存储设备最重要的操作无非就是读写操作,读即是将会话从存储设备加载到内存中,而写则将会话写入存储设备中,所以定义了两个重要的方法load和save与之相对应。FileStore和JDBCStore只要扩展Store接口各自实现load和save方法即可分别实现以文件或数据库形式存储会话。

这篇关于SpringSession深入浅出(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

深入浅出SRS—RTMP实现

RTMP 直播是 SRS 最典型的使用场景,客户端使用 RTMP 协议向 SRS 推流,使用 RTMP 协议从 SRS 拉流,SRS 作为一个 RTMP 直播服务器实现媒体的转发。同时,RTMP 是 SRS 的中转协议,其他协议之间的互通需要先转为 RTMP,因此,理解 SRS RTMP 直播实现是理解其他协议实现的重要前提。本文主要分析 SRS RTMP 直播功能的实现原理,相关概念和配置请参考

深入浅出Java垃圾回收机制

对于Java开发人员来说,了解垃圾回收机制(GC)有哪些好处呢?首先可以满足作为一名软件工程师的求知欲,其次,深入了解GC如何工作可以帮你写出更好的Java应用。   这仅仅代表我个人的意见,但我坚信一个精通GC的人往往是一个好的Java开发者。如果你对GC的处理过程感兴趣,说明你已经具备较大规模应用的开发经验。如果你曾经想过如何正确的选择GC算法,那意味着你已经完全理解你所开发的应用的特点

springboot 联合redis实现session共享springsession (springMVC的在上一篇) [二〇一八年十一月十四日]]

1创建springboot工程: 这个就不bb了, 不过我只能用main方法跑, 用tomcat跑回报一个redis的getConfig异常, 不管了 2引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-redis</artifactId><version>1.

深入浅出Stream流

Java 8的新特性之一就是流stream,配合同版本出现的 Lambda ,使得操作集合(Collection)提供了极大的便利。 案例引入 在JAVA中,涉及到对数组、Collection等集合类中的元素进行操作的时候,通常会通过循环的方式进行逐个处理,或者使用Stream的方式进行处理。 假设遇到了这么一个需求:从给定句子中返回单词长度大于5的单词列表,按长度倒序输出,最多返回3个。

深入浅出Android中的MVP模式

MVP模式是在MVC模式的基础之上改进而来的。MVP模式分为:model,view,presenter三部分。三部分的关系如下图所示: 其中PresenterCompl实现IPresenter接口,PresenterCompl中的方法要改变view时通过调用IView中的方法来实现。Model层为PresenterCompl提供数据。 也就是说之前MVC中view的控制都是在activit

[Cocoa]深入浅出 Cocoa 之 Core Data(2)- 手动编写代码

深入浅出 Cocoa 之 Core Data(2)- 代码示例 罗朝辉( http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 前面 详细讲解了 Core Data 的框架以及设计的类,下面我们来讲解一个完全手动编写代码使用这些类的示例,这个例子来自苹果官方示例。在这个例子里面,我们打算做这样一件事情:记录程序运行记录(时间与 proc

带你深入浅出之QT编程:一、掌握信号与槽的奥秘

此为QT编程的第一谈!关注我,带你快速学习QT编程的学习路线! 每一篇的技术点都是很很重要!很重要!很重要!但不冗余! 我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点! 码农不易,各位学者学到东西请点赞支持支持! 开始部分: 总:信号与槽,简单来说:信号就是事件,槽就是函数。信号只需声明,不需要实现,槽函数需要实现。(重中之中,开发过程中贯穿此机制) 就像我去咖啡厅点餐(

深入浅出:关系数据库中的基础概念与形式化定义

关系数据库是现代数据管理系统的核心,而理解关系数据库的基础概念是学习和应用这一技术的第一步。在这篇文章中,我们将通过简洁明了的解释,帮助您掌握关系的形式化定义及其相关概念。 1. 什么是关系模型? 关系模型是数据库管理系统中用于组织和管理数据的一种模型。它以二维表的形式表示数据,表中的每一行代表一个实体或记录,而每一列则代表一个属性或字段。 1.1 关系模型的基础 在关系模型中,数据的组织

【vSphere 7/8】深入浅出 vSphere 证书 Ⅲ—— vSphere 证书的更新和替换概述

目录 摘要1. vSphere Certificate Architecture2. 证书更新和替换概述2.1更新 VMCA 签名的证书(1)使用 vSphere Client UI(2)使用 vSphere Certificate Manager 命令行工具(自动)(3)使用 dir-cli、certool 和 vecs-cli 命令行工具(手动)(4)使用 vSphere Automat

O'Reilly之深入浅出Head First系列的中文版与英文版合集

来源url:http://blog.csdn.net/torchfire/article/details/12320479 Head First系列是O’Reilly出版社最成功的系列图书,自问世以来受到了无数读者的喜爱,并屡获大奖。其图文并茂,讲述编程技术由浅到深,也被称为“深入浅出”系列,是不可多得的各阶段程序员的参考学习资料。 收藏的中文版:  深入浅出数据分析(美