spring boot 分布式session实现
spring boot 分布式session实现
主要是通过包装HttpServletRequest
将session
相关的方法进行代理。
具体是的实现就是通过SessionRepositoryFilter
过滤器将HttpServletRequest
对象进行包装,当调用session
相关的方法时,代理到SessionRepository
的实现类。
我们先看看SessionRepository
。
public interface SessionRepository<S extends Session> {
//创建session
S createSession();
//保存session
void save(S session);
//通过session Id查找session
S findById(String id);
//通过session Id删除session
void deleteById(String id);
}
SessionRepository
是一个接口,主要用来管理session
。各种分布式session
处理方案都需要实现这个接口来实现具体的处理。
SessionRepositoryFilter
是一个过滤器,它的构造方法会接收一个SessionRepository
的实现类,并且在它的filter方法中会对HttpServletRequest
、HttpServletResponse
进行包装,当后续调用到session
相关的方法时,最终都会调用到SessionRepository
方法。
SessionRepositoryFilter
继承了OncePerRequestFilter
OncePerRequestFilter
是一个抽象类,需要子类来实现doFilterInternal
方法来实现。这个抽象类主要用来控制每个filter
只执行一次。在它的doFilter
方法中,又会调用到doFilterInternal
这个抽象方法。
这个是SessionRepositoryFilter
的构造方法
public SessionRepositoryFilter(SessionRepository<S> sessionRepository) {
if (sessionRepository == null) {
throw new IllegalArgumentException("sessionRepository cannot be null");
}
this.sessionRepository = sessionRepository;
}
这个是SessionRepositoryFilter
的doFilterInternal
方法,在这个方法中可以看到分别将request
,response
进行了包装,在这之后获取的request
,response
实际上是SessionRepositoryRequestWrapper
、SessionRepositoryResponseWrapper
类型。
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response);
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,
response);
try {
filterChain.doFilter(wrappedRequest, wrappedResponse);
}
finally {
wrappedRequest.commitSession();
}
}
之后调用request.getSesion()
之类session
相关的方法实际都会调用到SessionRepositoryRequestWrapper
的方法。
SessionRepositoryRequestWrapper
是SessionRepositoryFilter
的内部类,所以虽然在doFilterInternal
方法中创建SessionRepositoryRequestWrapper
对象时,没有传递SessionRepository
,但它依旧是可以使用的。
下面简单看下SessionRepositoryRequestWrapper
的getSession
方法
@Override
public HttpSessionWrapper getSession() {
return getSession(true);
}
@Override
public HttpSessionWrapper getSession(boolean create) {
......
//不相关的代码已经省略,如果对应的session已经存在,就会从上面省略的地方返回对应的session。
//如果session不存在,就会在下面去创建session。
//可以看到这里是通过SessionRepositoryFilter.this.sessionRepository来创建的
S session = SessionRepositoryFilter.this.sessionRepository.createSession();
session.setLastAccessedTime(Instant.now());
currentSession = new HttpSessionWrapper(session, getServletContext());
setCurrentSession(currentSession);
return currentSession;
}
spring的文档也写了如何使用redis和数据库来实现分布式session。当然spring也已经实现了redis和数据库的具体实现。我们仅仅使用配置就可以来使用。
具体的文档可以查看这里https://docs.spring.io/spring-session/docs/2.2.x/reference/html/httpsession.html#httpsession-redis-jc
比如使用redis来做分布式session
我们只需要进行下面几步
1、配置redis连接的相关信息
2、通过配置启动redis session相关
上面我分别标注了1、2、3。
我们分别来看看。
标注1:先看下
EnableRedisHttpSession
注解
这个类会通过Import
注解导入RedisHttpSessionConfiguration
类。而RedisHttpSessionConfiguration
类又是继承了SpringHttpSessionConfiguration
。
在RedisHttpSessionConfiguration
中会实现具体的session
管理的相关工作。它会创建一个类型为RedisIndexedSessionRepository
的bean。这个bean就实现了我们开头提到的SessionRepository
接口,用来执行具体的session
管理的相关工作。比如将session
保存到redis
,从redis
查找、删除对应session
等等具体的工作。
在SpringHttpSessionConfiguration
中会通过注入上面创建的RedisIndexedSessionRepository
的bean
,创建SessionRepositoryFilter
过滤器。
各种分布式实现方案一般都是通过这种方式来实现的。实现具体的
session
管理工作。通过SpringHttpSessionConfiguration
来完成其他工作。使用数据库做分布式session的时候也是继承
SpringHttpSessionConfiguration
。
标注2:这个是通过我们在yml中的配置来得到redis的连接工厂
标注3:这个主要是用来指定redis序列化的实现。
上面的是RedisHttpSessionConfiguration
的方法,在创建RedisTemplate
、RedisIndexedSessionRepository
时,都会判断defaultRedisSerializer
是否为null,不是null的情况下,会设置到RedisTemplate
、RedisIndexedSessionRepository
上去。默认的序列化实现,在我们在redis直接查看的时候,就会显示乱码。如下图:
注意:这里我们可以看到
RedisTemplate
并不是通过注入的方式来实现的。所以我们在外面创建RedisTemplate
的bean对象,在这里时用不到的。
所以就需要我们通过指定序列化实现,注入到defaultRedisSerializer
属性上。在RedisHttpSessionConfiguration
这个类中正好有注入的方法:
所以我们就可以在我们的代码中生成RedisSerializer
类型的bean
,同时指定bean
的名字为springSessionDefaultRedisSerializer
,就可以注入上去。
现在我们在redis查看session时,就不是乱码了。
其他如使用数据库或其他方案来实现分布式session,基本都和redis是类似的。
不过由于各种数据库的语法、等等各方面会稍有差异,所以每个数据库的session的建表语句都是不同的。如文档上所说,需要指定数据库类型和建表脚本。
spring boot 分布式session实现的更多相关文章
- Spring Boot 分布式Session状态保存Redis
在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而打到另外一台服务器的时候,session丢失. 常规的解决方 ...
- (38)Spring Boot分布式Session状态保存Redis【从零开始学Spring Boot】
[本文章是否对你有用以及是否有好的建议,请留言] 在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而访问到另外 ...
- spring boot分布式技术,spring cloud,负载均衡,配置管理器
spring boot分布式的实现,使用spring cloud技术. 下边是我理解的spring cloud的核心技术: 1.配置服务器 2.注册发现服务器eureka(spring boot默认使 ...
- Spring Cloud分布式Session共享实践
通常情况下,Tomcat.Jetty等Servlet容器,会默认将Session保存在内存中.如果是单个服务器实例的应用,将Session保存在服务器内存中是一个非常好的方案.但是这种方案有一个缺点, ...
- Spring Boot2 系列教程(二十八)Spring Boot 整合 Session 共享
这篇文章是松哥的原创,但是在第一次发布的时候,忘了标记原创,结果被好多号转发,导致我后来整理的时候自己没法标记原创了.写了几百篇原创技术干货了,有一两篇忘记标记原创进而造成的一点点小小损失也能接受,不 ...
- spring boot 分布式事务实现(XA方式)
关于spring boot 支持分布式事务,XA是常用的一种方式. 这里把相关的配置记下,方便以后使用. 首先配置两个不同的数据源 : 订单库.持仓库. /** * Created by zhangj ...
- spring boot 分布式锁组件 spring-boot-klock-starter
基于redis的分布式锁spring-boot starter组件,使得项目拥有分布式锁能力变得异常简单,支持spring boot,和spirng mvc等spring相关项目 快速开始 sprin ...
- spring boot redis session
1. pom.xml 这里 spring parent的版本 2.1.5会报错 2.1.0和2.1.4经过测试正常 <?xml version="1.0" encoding= ...
- 2020最新的Spring Boot 分布式锁的具体实现(内附代码)
前言 面试总是会被问到有没有用过分布式锁.redis 锁,大部分读者平时很少接触到,所以只能很无奈的回答 "没有".本文通过 Spring Boot 整合 redisson 来实现 ...
随机推荐
- 最短路之 Dijkstra 算法
普通的 Dijkstra 这是一种运用贪心的单源最短路算法,就是求从一个节点出发,到任意一个点的最短距离 首先我们要一个图 假设要求从 1 开始的单源最短路 dis[] 表示最短路数组, vis[] ...
- 如何使用lerna进行多包(package)管理
为什么要用lerna 将大型代码仓库分割成多个独立版本化的 软件包(package)对于代码共享来说非常有用.但是,如果某些更改 跨越了多个代码仓库的话将变得很 麻烦 并且难以跟踪,并且, 跨越多个代 ...
- Error: $controller:ctrlreg A controller with this name is not registered.
The controller with the name 'SomeController' is not registered.名称为'SomeController'的控制器没注册 : Descrip ...
- windows 2003系统安装
一.使用workstation创建虚拟机 二.系统安装 点击"Enter" 点击"F8" 点击"Enter" 如下图所示: 点击" ...
- Redis系列2:数据持久化提高可用性
1 介绍 从上一篇的 <深刻理解高性能Redis的本质> 中可以知道, 我们经常在数据库层上加一层缓存(如Redis),来保证数据的访问效率. 这样性能确实也有了大幅度的提升,但是本身Re ...
- RPA跨系统自动生成采购订单
1.从开发器启动机器人 2.RPA登录友采云 3.RPA根据筛选条件,导出采购订单 4.RPA请并登录NC 5.RPA把读取到的数据,逐个录入到NC系统中,并存储到Excel中 6.RPA将最终的Ex ...
- ansible管理windows主机
1. 在windows开启winrm winrm service 默认都是未启用的状态,先查看状态:如无返回信息,则是没有启动: winrm enumerate winrm/config/listen ...
- HDFS存储目录分析
一.介绍 HDFS metadata以树状结构存储整个HDFS上的文件和目录,以及相应的权限.配额和副本因子(replication factor)等.本文基于Hadoop2.6版本介绍HDFS Na ...
- Node.js精进(8)——错误处理
在 Node.js 中,提供了 error 模块,并且内置了标准的 JavaScript 错误,常见的有: EvalError:在调用 eval() 函数时出现问题时抛出该错误. SyntaxErro ...
- Tapdata 携手精诚瑞宝,共拓 Real Time DaaS 蓝海市场
2021年10月22日,深圳钛铂数据有限公司「Tapdata」 与精诚瑞宝计算机系统有限公司「精诚瑞宝」战略合作签约仪式在深圳举行,Tapdata 创始人唐建法先生与精诚瑞宝副总经理余灿雄先生签署 ...