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的获取、保存和清理
@GetMapping("/") public String process(Model model, HttpSession session) { @SuppressWarnings("unchecked") List<String> messages = (List<String>) session.getAttribute("springSession"); if (messages == null) { messages = new ArrayList<>(); } model.addAttribute("sessionMessages", messages); return "sessionTest"; } @PostMapping("/persistSession") public String persistMessage(@RequestParam("msg") String msg, HttpServletRequest request) { @SuppressWarnings("unchecked") List<String> messages = (List<String>) request.getSession().getAttribute("springSession"); if (messages == null) { messages = new ArrayList<>(); request.getSession().setAttribute("springSession", messages); } messages.add(msg); request.getSession().setAttribute("springSession", messages); return "redirect:/"; } @PostMapping("/destroySession") public String destroySession(HttpServletRequest request) { request.getSession().invalidate(); return "redirect:/"; }
sessionTest.html对应页面操作
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Spring Boot Session Example</title> </head> <body> <div> <form th:action="@{/persistSession}" method="post"> <textarea name="msg" cols="40" rows="2"></textarea> <br> <input type="submit" value="保存" /> </form> </div> <div> <h2>session列表</h2> <ul th:each="message : ${sessionMessages}"> <li th:text="${message}">message</li> </ul> </div> <div> <form th:action="@{/destroySession}" method="post"> <input type="submit" value="清空" /> </form> </div> </body> </html>
基于数据库的Spring-Session
1.引入maven依赖
使用MySQL存储,所以引入了MySQL。
涉及到SpringBoot JDBC的配置,引入了Spring Boot JDBC Starter。
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-core</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-jdbc</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.18</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </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配置。
# 配置数据源相关内容 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring_learn?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false spring.datasource.username=xxx spring.datasource.password=xxx spring.datasource.initialization-mode=always # session类型选择jdbc spring.session.store-type=jdbc spring.session.jdbc.initialize-schema=always # 指定表名 #spring.session.jdbc.table-name=SESSIONS # 超时时间 spring.session.timeout=180s
3.数据库存储解析
默认情况下,数据库中会创建2张表。SPRING_SESSION和SPRING_SESSION_ATTRIBUTION。
SPRING_SESSION用于存在session自身的一些属性,如创建时间、过期时间等,详细schema如下。
CREATE TABLE `SPRING_SESSION` ( `PRIMARY_ID` char(36) NOT NULL, `SESSION_ID` char(36) NOT NULL, `CREATION_TIME` bigint NOT NULL, `LAST_ACCESS_TIME` bigint NOT NULL, `MAX_INACTIVE_INTERVAL` int NOT NULL, `EXPIRY_TIME` bigint NOT NULL, `PRINCIPAL_NAME` varchar(100) DEFAULT NULL, PRIMARY KEY (`PRIMARY_ID`), UNIQUE KEY `SPRING_SESSION_IX1` (`SESSION_ID`), KEY `SPRING_SESSION_IX2` (`EXPIRY_TIME`), KEY `SPRING_SESSION_IX3` (`PRINCIPAL_NAME`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC
SPRING_SESSION_ATTRIBUTION用于存储session相关联的属性,schema如下。
CREATE TABLE `SPRING_SESSION_ATTRIBUTES` ( `SESSION_PRIMARY_ID` char(36) NOT NULL, `ATTRIBUTE_NAME` varchar(200) NOT NULL, `ATTRIBUTE_BYTES` blob NOT NULL, PRIMARY KEY (`SESSION_PRIMARY_ID`,`ATTRIBUTE_NAME`), CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC
4.测试执行
SPRING_SESSION中的数据
SPRING_SESSION_ATTRIBUTION中的数据。
基于Redis的Spring-Session
几乎同样的步骤
maven依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
application.properties配置
spring.session.store-type=redis spring.redis.host=127.0.0.1 spring.redis.port=6379
结果分析
一次请求后,多了三个属性,分析如下。
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中的注释。
订阅Spring-Session的相关事件
有些时候,我们比较关心Session的创建或者销毁事件,做一些特殊的处理或者记录。基于Redis的Spring-Session利用Spring Event将该事件发布出来,我们可以使用EventListener监听做处理。
@Component @Slf4j public class AnnotationDrivenEventListener { @EventListener public void handleSessionCreated(SessionCreatedEvent sessionCreatedEvent) { String sessionId = sessionCreatedEvent.getSessionId(); log.info("session id:{} created", sessionId); } @EventListener public void handleSessionDestroyed(SessionDestroyedEvent sessionDestroyedEvent) { String sessionId = sessionDestroyedEvent.getSessionId(); log.info("session id:{} destroyed", sessionId); } }
总结
Spring Session提供了非常便利的,基于关系型数据库或者Redis的Session解决方案。
Redis版访问速度快,基于Redis的过期策略,保证过期数据会被删除,同时支持事件订阅。
数据库版直接基于数据库,无需单独引入其他存储。但是访问速度相对较慢,过期数据需要依赖应用程序自身进行删除。同时没有提供事件订阅能力。
以上就是Spring Session的使用示例的详细内容,更多关于Spring Session的使用的资料请关注猪先飞其它相关文章!
相关文章
PHP session_start()很慢问题分析与解决办法
本文章来给各位同学介绍一下关于PHP session_start()很慢问题分析与解决办法,希望碰到此问题的同学可进入参考。 最近在做东西的时候发现一个问题 有一个接口挂...2016-11-25- 这篇文章主要介绍了Spring AOP 对象内部方法间的嵌套调用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-08-29
Spring Cloud 中@FeignClient注解中的contextId属性详解
这篇文章主要介绍了Spring Cloud 中@FeignClient注解中的contextId属性详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-25Springboot如何实现Web系统License授权认证
这篇文章主要介绍了Springboot如何实现Web系统License授权认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-28如何在Spring WebFlux的任何地方获取Request对象
这篇文章主要介绍了如何在Spring WebFlux的任何地方获取Request对象,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下...2021-01-26- 这篇文章主要介绍了详解SpringCloudGateway内存泄漏问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-07-16
PHP分布式框架如何使用Memcache同步SESSION教程
本教程主要讲解PHP项目如何用实现memcache分布式,配置使用memcache存储session数据,以及memcache的SESSION数据如何同步。 至于Memcache的安装配置,我们就不讲了,以前...2016-11-25- @Autowired 注解的主要功能就是完成自动注入,使用也非常简单,但这篇文章主要给大家介绍了关于Spring为什么不推荐使用@Autowired注解的相关资料,需要的朋友可以参考下...2021-11-03
Springboot如何使用mybatis实现拦截SQL分页
这篇文章主要介绍了Springboot使用mybatis实现拦截SQL分页,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-06-19- 这篇文章主要介绍了C#中的session用法 ,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下...2020-06-25
Python3使用Selenium获取session和token方法详解
这篇文章主要介绍了Python3使用Selenium获取session和token方法详解,需要的朋友可以参考下...2021-02-17- 这篇文章主要介绍了SpringMVC文件上传原理及实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-07-15
Spring Data JPA 关键字Exists的用法说明
这篇文章主要介绍了Spring Data JPA 关键字Exists的用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-10tomcat启动完成执行 某个方法 定时任务(Spring)操作
这篇文章主要介绍了tomcat启动完成执行 某个方法 定时任务(Spring)操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-25使用Maven 搭建 Spring MVC 本地部署Tomcat的详细教程
这篇文章主要介绍了使用Maven 搭建 Spring MVC 本地部署Tomcat,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-08-16- 这篇文章主要介绍了Spring Cloud负载均衡及远程调用实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2021-09-18
- session和cookie是网站浏览中较为常见的两个概念,也是比较难以辨析的两个概念,但它们在点击流及基于用户浏览行为的网站分析中却相当关键。基于网上一些文章和资料的参阅,及作者个人的应用体会,对这两个概念做一个简单的阐述...2013-09-11
- 这篇文章主要介绍了SpringMvc自动装箱及GET请求参数原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-19
- 这篇文章主要介绍了SpringMvc获取请求头请求体消息过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-17
- 这篇文章主要介绍了Springboot使用thymeleaf动态模板实现刷新,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-08-31