spring boot 分布式session实现

主要是通过包装HttpServletRequestsession相关的方法进行代理。

具体是的实现就是通过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方法中会对HttpServletRequestHttpServletResponse进行包装,当后续调用到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;
}

这个是SessionRepositoryFilterdoFilterInternal方法,在这个方法中可以看到分别将request,response进行了包装,在这之后获取的request,response实际上是SessionRepositoryRequestWrapperSessionRepositoryResponseWrapper类型。

	@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的方法。

SessionRepositoryRequestWrapperSessionRepositoryFilter的内部类,所以虽然在doFilterInternal方法中创建SessionRepositoryRequestWrapper对象时,没有传递SessionRepository,但它依旧是可以使用的。


下面简单看下SessionRepositoryRequestWrappergetSession方法

		@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中会通过注入上面创建的RedisIndexedSessionRepositorybean,创建SessionRepositoryFilter过滤器。

各种分布式实现方案一般都是通过这种方式来实现的。实现具体的session管理工作。通过SpringHttpSessionConfiguration来完成其他工作。

使用数据库做分布式session的时候也是继承SpringHttpSessionConfiguration

  • 标注2:这个是通过我们在yml中的配置来得到redis的连接工厂

  • 标注3:这个主要是用来指定redis序列化的实现。

上面的是RedisHttpSessionConfiguration的方法,在创建RedisTemplateRedisIndexedSessionRepository时,都会判断defaultRedisSerializer是否为null,不是null的情况下,会设置到RedisTemplateRedisIndexedSessionRepository上去。默认的序列化实现,在我们在redis直接查看的时候,就会显示乱码。如下图:

注意:这里我们可以看到RedisTemplate并不是通过注入的方式来实现的。所以我们在外面创建RedisTemplate的bean对象,在这里时用不到的。

所以就需要我们通过指定序列化实现,注入到defaultRedisSerializer属性上。在RedisHttpSessionConfiguration这个类中正好有注入的方法:

所以我们就可以在我们的代码中生成RedisSerializer类型的bean,同时指定bean的名字为springSessionDefaultRedisSerializer,就可以注入上去。

现在我们在redis查看session时,就不是乱码了。


其他如使用数据库或其他方案来实现分布式session,基本都和redis是类似的。

不过由于各种数据库的语法、等等各方面会稍有差异,所以每个数据库的session的建表语句都是不同的。如文档上所说,需要指定数据库类型和建表脚本。

spring boot 分布式session实现的更多相关文章

  1. Spring Boot 分布式Session状态保存Redis

    在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而打到另外一台服务器的时候,session丢失. 常规的解决方 ...

  2. (38)Spring Boot分布式Session状态保存Redis【从零开始学Spring Boot】

    [本文章是否对你有用以及是否有好的建议,请留言] 在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而访问到另外 ...

  3. spring boot分布式技术,spring cloud,负载均衡,配置管理器

    spring boot分布式的实现,使用spring cloud技术. 下边是我理解的spring cloud的核心技术: 1.配置服务器 2.注册发现服务器eureka(spring boot默认使 ...

  4. Spring Cloud分布式Session共享实践

    通常情况下,Tomcat.Jetty等Servlet容器,会默认将Session保存在内存中.如果是单个服务器实例的应用,将Session保存在服务器内存中是一个非常好的方案.但是这种方案有一个缺点, ...

  5. Spring Boot2 系列教程(二十八)Spring Boot 整合 Session 共享

    这篇文章是松哥的原创,但是在第一次发布的时候,忘了标记原创,结果被好多号转发,导致我后来整理的时候自己没法标记原创了.写了几百篇原创技术干货了,有一两篇忘记标记原创进而造成的一点点小小损失也能接受,不 ...

  6. spring boot 分布式事务实现(XA方式)

    关于spring boot 支持分布式事务,XA是常用的一种方式. 这里把相关的配置记下,方便以后使用. 首先配置两个不同的数据源 : 订单库.持仓库. /** * Created by zhangj ...

  7. spring boot 分布式锁组件 spring-boot-klock-starter

    基于redis的分布式锁spring-boot starter组件,使得项目拥有分布式锁能力变得异常简单,支持spring boot,和spirng mvc等spring相关项目 快速开始 sprin ...

  8. spring boot redis session

    1. pom.xml 这里 spring parent的版本 2.1.5会报错 2.1.0和2.1.4经过测试正常 <?xml version="1.0" encoding= ...

  9. 2020最新的Spring Boot 分布式锁的具体实现(内附代码)

    前言 面试总是会被问到有没有用过分布式锁.redis 锁,大部分读者平时很少接触到,所以只能很无奈的回答 "没有".本文通过 Spring Boot 整合 redisson 来实现 ...

随机推荐

  1. 获取mybatis注解方式新增数据时非自增插入的主键

    场景:插入数据的时候,获取不到非自增的主键.原因:对象中没有主键的值,插入后主键才有值. 解决方案:使用 @SelectKey @SelectKey中: statement是要运行的SQL语句,即查询 ...

  2. VisionPro · C# · 创建项目

    将 VisionPro 引入 C# 项目程序中需要执行以下操作: 1.更改项目程序.NET框架: 2.添加编程引用: 3.添加界面设计控件引用: VisionPro 不同版本对应不同的 .NET 框架 ...

  3. C4C UI Design背景色

  4. NC50965 Largest Rectangle in a Histogram

    NC50965 Largest Rectangle in a Histogram 题目 题目描述 A histogram is a polygon composed of a sequence of ...

  5. java中的变量及命名

    变量 变量顾名思义就是可以变化的量 因为java是强类型语言,所以每个变量都必须声明其类型 java变量是最基本的存储单元,要素包括变量名称,变量类型和作用域. 目录 变量 1.常用的变量创建 2.变 ...

  6. 拥抱云原生 2.0 时代,Tapdata 入选阿里云首期云原生加速器!

      3月9日,阿里云首期云原生加速器官宣,Tapdata 突出重围,成功入选31 强,将与多家行业知名企业,携手阿里云共建云原生行业新生态,加速拥抱云原生新时代的无限潜能.   2021年,阿里云正式 ...

  7. Three.js系列: 在元宇宙看电影,享受 VR 视觉盛宴

    本文 gihtub 地址: https://github.com/hua1995116/Fly-Three.js 最近元宇宙的概念很火,并且受到疫情的影响,我们的出行总是受限,电影院也总是关门,但是在 ...

  8. mybatis-拦截器实际应用-替换表名-2022新项目

    一.业务场景 考虑到新项目中部分与业务数据相关的表在后期数据量会比较大,架构师在最开始设计项目中与业务数据相关的表时,就已经考虑使用分表来 进行处理,给业务数据相关的每张表都添加统一批次的后缀,查询这 ...

  9. NOI / 1.1编程基础之输入输出全题详解(8515字)

    目录 01:Hello, World! 02:输出第二个整数 03:对齐输出 04:输出保留3位小数的浮点数

  10. 如何创建一个带诊断工具的.NET镜像

    现阶段的问题 现在是云原生和容器化时代,.NET Core对于云原生来说有非常好的兼容和亲和性,dotnet社区以及微软为.NET Core提供了非常方便的镜像容器化方案.所以现在大多数的dotnet ...