spring-session-data-redis解决session共享的问题
分布式系统要做到用户友好,需要对用户的session进行存储,存储的方式有以下几种:
本地缓存
数据库
文件
缓存服务器
可以看一些不同方案的优缺点
1.本地机器或者本地缓存。优点:速度快 缺点:服务宕机后重启用户信息丢失,用户不优好
2.数据库。优点:技术栈简单 缺点:速度慢
3.文件。优点:技术栈简单,速度适中 缺点:无灾备或者灾备方案成本高
4.缓存服务器。一般是内存服务器,优点:速度快 可以和原有技术栈契合,有现成的解决方案。缺点:不明显
如果使用java语言,并且缓存服务器为redis,可以使用开源的spring session项目来解决。
spring session项目现有三个自项目,分别是
spring-session-data-redis 使用redis方式
spring-session-hazelcast 使用hazelcast方式
spring-session-jdbc 使用jdbc方式
在这里我建议大家使用redis方式,它提供了注解式和编程式不同的方法。具体如何使用,网上有很多实例,我就不赘述。我想和大家一起深入内部看一下,spring-session项目的github地址为:https://github.com/spring-projects/spring-session.git
我们只看spring-session-data-redis,实现非常简单。它总共只有12个类
核心类只有一个
RedisOperationsSessionRepository
这个类内部定义了session的实现
RedisSession
/** * A custom implementation of {@link Session} that uses a {@link MapSession} as the * basis for its mapping. It keeps track of any attributes that have changed. When * {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#saveDelta()} * is invoked all the attributes that have been changed will be persisted. * * @author Rob Winch * @since 1.0 */
final class RedisSession implements Session { private final MapSession cached; private Instant originalLastAccessTime; private Map<String, Object> delta = new HashMap<>(); private boolean isNew; private String originalPrincipalName; private String originalSessionId;
注意:
delta 是增量 cached是存量
我们来看这个RedisSession的创建 销毁及修改
RedisSession内部存储如下(示例)
* <pre>* HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 maxInactiveInterval 1800 lastAccessedTime 1404360000000 sessionAttr:attrName someAttrValue sessionAttr2:attrName someAttrValue2* EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100* APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""* EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800* SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe* EXPIRE spring:session:expirations1439245080000 2100* </pre>
RedisSession的数据结构是Hash
* <p>* Each session is stored in Redis as a* <a href="http://redis.io/topics/data-types#hashes">Hash</a>. Each session is set and* updated using the <a href="http://redis.io/commands/hmset">HMSET command</a>. An* example of how each session is stored can be seen below.* </p>
RedisSession的失效
* <h3>Expiration</h3>** <p>* An expiration is associated to each session using the* <a href="http://redis.io/commands/expire">EXPIRE command</a> based upon the* {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#getMaxInactiveInterval()}* . For example:* </p>
RedisSession的更新有一个比较重要的方法:
/** * Saves any attributes that have been changed and updates the expiration of this * session. */private void saveDelta() { String sessionId = getId(); saveChangeSessionId(sessionId); if (this.delta.isEmpty()) { return; } getSessionBoundHashOperations(sessionId).putAll(this.delta); String principalSessionKey = getSessionAttrNameKey( FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); String securityPrincipalSessionKey = getSessionAttrNameKey( SPRING_SECURITY_CONTEXT); if (this.delta.containsKey(principalSessionKey) || this.delta.containsKey(securityPrincipalSessionKey)) { if (this.originalPrincipalName != null) { String originalPrincipalRedisKey = getPrincipalKey( this.originalPrincipalName); RedisOperationsSessionRepository.this.sessionRedisOperations .boundSetOps(originalPrincipalRedisKey).remove(sessionId); } String principal = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this); this.originalPrincipalName = principal; if (principal != null) { String principalRedisKey = getPrincipalKey(principal); RedisOperationsSessionRepository.this.sessionRedisOperations .boundSetOps(principalRedisKey).add(sessionId); } } this.delta = new HashMap<>(this.delta.size()); Long originalExpiration = (this.originalLastAccessTime != null) ? this.originalLastAccessTime.plus(getMaxInactiveInterval()) .toEpochMilli() : null; RedisOperationsSessionRepository.this.expirationPolicy .onExpirationUpdated(originalExpiration, this);}
小结:
1.session是键值对形式的,对应redis的数据结构hash
2.session的存储形式使用redis非常方便
转载于:https://www.cnblogs.com/davidwang456/p/10172841.html
spring-session-data-redis解决session共享的问题相关推荐
- 170222、使用Spring Session和Redis解决分布式Session跨域共享问题
使用Spring Session和Redis解决分布式Session跨域共享问题 原创 2017-02-27 徐刘根 Java后端技术 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用 ...
- 使用Spring Session和Redis解决分布式Session跨域共享问题
大家可以关注一下公众号"Java架构师秘籍" 前言 对于分布式使用Nginx+Tomcat实现负载均衡,最常用的均衡算法有IP_Hash.轮训.根据权重.随机等.不管对于哪一种负载 ...
- Spring boot - 使用redis实现session共享
在分布式系统架构的系统中,我们如何保证session的一致性,其中之一的解决方式就是session共享形式,在SpringBoot框架中如何使用session达成共享呢,我们可以借助指定Redis实现 ...
- Spring boot集成Redis实现sessions共享时,sessions过期时间问题分析
Springboot鼓励零配置的方式,帮你做好大部分重复劳动的事,好到不能再好:具体的Redis安装方法和Springboot集成Redis方法,可以去搜索相关文章或参考该文章http://www.c ...
- php session存到redis,php Session存储到Redis的方法
php Session存储到Redis的方法 当然要写先安装php的扩展,可参考这篇文章:Redis及PHP扩展安装修改php.ini的设置 复制代码 代码如下: session.save_handl ...
- spring boot 整合redis实现session共享
目录 官方文档,它是spring session项目的redis相关的一个子文档:https://docs.spring.io/spring-session/docs/2.0.0.BUILD-SNAP ...
- Spring mvc Data Redis—Pub/Sub(附Web项目源码)
一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...
- 单点登录实现(spring session+redis完成session共享)
一.前言 项目中用到的SSO,使用开源框架cas做的.简单的了解了一下cas,并学习了一下 单点登录的原理,有兴趣的同学也可以学习一下,写个demo玩一玩. 二.工程结构 我模拟了 sso的客户端和s ...
- spring session通过redis存储,实现session共享
目录 前言 1 准备工作 1.1 spring框架的jar包 1.2 spring session的相关jar包 2 具体步骤 2.1 创建项目 2.2 spring mvc的配置 2.3 sprin ...
- spring-session用redis实现session共享实践
什么是spring session? Spring Session provides an API and implementations for managing a user's session ...
最新文章
- Windows Phone开发:常用控件(上)
- Android中的各种Adapter
- 部署在SAP ABAP服务器上的SAP UI5应用的JavaScript文件,是如何被SAP UI5 repository handler处理的
- java中你知道的这四种代码块吗?
- Android点击返回键销毁自己,Activity界面销毁 软键盘未收回
- 空字符python_Python中的None与 NULL(即空字符)的区别详解
- anaconda安装pytorch1.7.1和torchvision0.8.2的方法,亲测可用
- 都在夸官方文档 Vue.js 2021 年度报告出炉!
- Python开源机器学习项目实战
- html设置字体样式罗马,罗马字体英文
- 复工后的前端学习建议,非常实用!
- 山东大学——国际结算方式
- [美国]《冰雪奇缘》[BD-RMVB.720p.中英双字][2013年高分获奖][奥斯卡提名动画片]
- matlab中counter怎么用,matlab中fspecial函数的用法
- sudo no tty present and no askpass program specified
- 【转】deepin Linux下Picked up _JAVA_OPTIONS错误
- Spark之spark VS MR
- 云计算事业部高性能集群使用手册
- 数学基础:斜率、正切与 math.tan()
- 是一个新的开始,还是冥冥之中已经在路上。
热门文章
- Spring第三讲:利用注解配置类取代Spring的配置文件
- java 链接占用太多_Java程序链接数过多导致java.net.SocketException: No buffer space available问题...
- php在页面循环输出标签,自定义页面循环
- alertdialog怎么水平排列_轻钢二级吊顶怎么安装
- 我的同学是计算机作文,同学相见作文
- mongodb聚合查询优化_MongoDB聚合查询详解
- android8.1状态栏图标,Android 8.1 去掉 Launcher3 默认给 icon 增加的白边
- Fragment碎片的基本使用(手机平板需要更好地兼容)
- 8种相似度度量方式的原理及实现【笔记自用】【1】
- c++ string类