首页 > 其他分享 >spring boot 分布式session实现

spring boot 分布式session实现

时间:2022-08-27 16:45:31浏览次数:49  
标签:SessionRepository sessionRepository 实现 spring boot redis SessionRepositoryFilter

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的建表语句都是不同的。如文档上所说,需要指定数据库类型和建表脚本。

标签:SessionRepository,sessionRepository,实现,spring,boot,redis,SessionRepositoryFilter
From: https://www.cnblogs.com/wbo112/p/16630865.html

相关文章

  • springboot+docker发布项目20220827
    1、springboot打包项目 1)、application-dev.yml     对应配置修改 2)、项目package 生成包    3)、生成包         4)、运行......
  • 04Spring MVC入门
    SpringMVC三层架构表现层业务层数据访问层MVC(处理表现层)Model:模型层View:视图层Controller:控制层底层请求方式在controller中添加@RequestMapping("/......
  • Spring boot 对接口限制IP访问次数
    1、需要的依赖<!--redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-star......
  • 什么是 Cookie 和 Session ?
    什么是Cookie和Session?什么是CookieHTTPCookie(也叫WebCookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器......
  • springBoot 获取注解参数的原理
    springBoot获取注解参数的原理原理图先得到请求的request在获取可以处理请求的方法的Mapping映射器DispatcherServlet中的doDispatch方法//De......
  • 日志打印输出到控制台以及文件 Spring boot application.yml https://www.cnblogs
    转自:https://www.cnblogs.com/izyh/p/15945950.htmlyml文件中添加配置:##########日志配置-START##########logging:config:classpath:logback-spring.......
  • phpStudy的session文件存储在哪里
    最近学习session,根据老师所讲,session文件存储在c:\windows\temp文件夹,但是找不到,利用百度查找发现具体存储位置在php.ini中,而我用的集成开发环境是phpStudy,就打开相应的ph......
  • JPA 入门实战(3)--Spring Boot 中使用 JPA
    本文主要介绍在SpringBoot中使用JPA的方法(暂不使用spring-data-jpa),相关的环境及软件信息如下:SpringBoot2.6.10、JPA2.2、eclipselink2.7.10。1、原生使用该......
  • 78、使用Jenkins Docker 部署SpringBoot项目
    1、centOS安装Docker1、更新软件源:yumupdate2、卸载旧版本:yumremovedockerdocker-commondocker-selinuxdocker-engine3、安装软件包:yuminstall-yyum-utils......
  • SpringBoot集成thymeleaf不生效问题
    场景:在做springBoot整合Theamleaf时,用了@RestController注解,在进行试图渲染的过程中,遇到试图没有渲染成功,找到了原因,记录一下。 第一种情况:使用@RestController注解pac......