最近团队一个项目需要使用Session,之前没有在实际项目中使用过Spring-Session,这里记录一下使用的过程。
Session
Http协议是无状态的,这样对于服务端来说,没有办法区分是新的访客还是旧的访客。但是,有些业务场景,需要追踪用户多个请求,此时就需要Session。关于session的百度百科session
Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的Web页之间跳转时,存储在Session对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的 Web页时,如果该用户还没有会话,则Web服务器将自动创建一个 Session对象。当会话过期或被放弃后,服务器将终止该会话
核心特点:
- 服务端存储
- 会过期
Session常用解决方案
对于Session的常用解决方案,可以划分为三种。
- 负载均衡方式
借助负载均衡设备或者模块,将指定的Session始终路由到同一台机器即可,如Nginx。
- 副本复制方式
利用服务器节点间的副本复制方式,保证集群所有节点拥有的Session数据一致。
- 集中存储方式
引入第三方存储,将Session数据集中存储到外部存储中,如Redis或者数据库等。
本文介绍的Spring-Session是采用第三种,集中存储的方式。
Spring-Session
核心组成模块
- Spring Session Core
提供Spring Session核心的功能和API
- Spring Session Data Redis
提供基于Redis的SessionRepository以及配置
- Spring Session JDBC
提供基于关系型数据库的SessionRepository以及配置
- Spring Session Hazelcast
提供基于Hazelcast的SessionRepository以及配置
测试代码
controller提供三个接口,分别对应Session的获取、保存和清理
1 | java复制代码 |
sessionTest.html对应页面操作
1 | html复制代码<!DOCTYPE html> |
基于数据库的Spring-Session
- 引入maven依赖
使用MySQL存储,所以引入了MySQL。
涉及到SpringBoot JDBC的配置,引入了Spring Boot JDBC Starter。
1 | xml复制代码<dependency> |
注意:
No session repository could be auto-configured, check your configuration (session store type is ‘jdbc’)
如果存在这个报错,是因为没有引入spring-boot-starter-jdbc,引入即可。
2. 配置application.properties文件
主要包含两部分,数据库的配置以及Spring Session Jdbc配置。
1 | properties复制代码# 配置数据源相关内容 |
- 数据库存储解析
默认情况下,数据库中会创建2张表。SPRING_SESSION和SPRING_SESSION_ATTRIBUTION。
SPRING_SESSION用于存在session自身的一些属性,如创建时间、过期时间等,详细schema如下。
1 | sql复制代码CREATE TABLE `SPRING_SESSION` ( |
SPRING_SESSION_ATTRIBUTION用于存储session相关联的属性,schema如下。
1 | sql复制代码CREATE TABLE `SPRING_SESSION_ATTRIBUTES` ( |
- 测试执行
SPRING_SESSION中的数据
SPRING_SESSION_ATTRIBUTION中的数据。
基于Redis的Spring-Session
几乎同样的步骤
- maven依赖
1 | xml复制代码<dependency> |
- application.properties配置
1 | properties复制代码spring.session.store-type=redis |
- 结果分析
一次请求后,多了三个属性,分析如下。
key | 类型 | 用途 | value |
---|---|---|---|
spring:session:sessions:expires:${sessionId} | string | 判断sesssion是否存在 | 空 |
spring:session:sessions:${sessionId} | hash | session相关的属性,包括有效期、创建时间、具体属性等 | creationTime/lastAccessedTime/sessionAttr/maxInactiveInterval |
spring:session:expirations:1623656160000 | set | 存储待过期的sessionId列表 | key: 过期的时间戳;value: 在这个时间戳将要过期的expire key列表。 |
在访问时,先通过第一个key,判断session是否存在以及是否过期。如果没有过期,可以通过第二个key获取或者更新对应的session详情。
对于第三个key,实际上Spring-Session-Redis会有特殊的用途,主要是为了Redis的keySpace-notificationhttps://redis.io/topics/notifications。核心目的是为了确保过期的session一定要触发过期事件。关于这方面的解释,可以看一下RedisIndexedSessionRepository中的注释。
4. 订阅Spring-Session的相关事件
有些时候,我们比较关心Session的创建或者销毁事件,做一些特殊的处理或者记录。基于Redis的Spring-Session利用Spring Event将该事件发布出来,我们可以使用EventListener监听做处理。
1 | java复制代码 |
总结
Spring Session提供了非常便利的,基于关系型数据库或者Redis的Session解决方案。
Redis版访问速度快,基于Redis的过期策略,保证过期数据会被删除,同时支持事件订阅。
数据库版直接基于数据库,无需单独引入其他存储。但是访问速度相对较慢,过期数据需要依赖应用程序自身进行删除。同时没有提供事件订阅能力。
参考文章
[1] www.javainuse.com/spring/spri…
[2] www.javainuse.com/spring/spri…
本文转载自: 掘金