spring session和mongoDB实现分布式session共享

时间:2021-10-01 06:08:14

spring session和mongoDB实现分布式session共享

研究背景

一方面是因为我们做token验证的时候是在zuul网关这边做的,用户认证通过后,需要对token的刷新来模拟session的功能,但遇到刷新后的值不能直接返回给浏览器的问题,一直没有找到很好的解决办法,第二方面就是大家对于session使用熟练,使用起来比token更加顺手。所以就研究了如何用spring session和MongoDB来实现分布式session的共享。

session和cookie简介

由于http协议是无状态的协议,为了能够记住请求的状态,于是引入了Session和Cookie的机制。我们应该有一个很明确的概念,那就是Session是存在于服务器端的,它是由tomcat管理的,存在于tomcat的内存中。而Cookie则是存在于客户端,更方便理解的说法,可以说存在于浏览器。http协议允许从服务器返回Response时携带一些Cookie,并且同一个域下对Cookie的数量有所限制,之前说过Session的持久化依赖于服务端的策略,而Cookie的持久化则是依赖于本地文件。有一类特殊的Cookie我们需要额外关注,那便是与Session相关的sessionId,他是真正维系客户端和服务端的桥梁。

分布式session简介

由于一般session只存在与单体应用中,当遇到分布式系统时,就会出现session不能共享的问题。这时就需要借助外部存储工具,将服务器上产生的session复制到该外部存储工具上面,以此实现不同服务器上共享同一个session,这就叫做分布式session。

下图是一般单体应用中session的工作原理图
spring session和mongoDB实现分布式session共享
下图是分布式session的工作原理图
spring session和mongoDB实现分布式session共享

分布式session的实现思路

核心思路:就是替换掉servlet容器创建和管理session的实现

实现方案

1.利用Servlet容器提供的插件功能,自定义HttpSession的创建和管理策略,并通过配置的方式替换掉默认的策略。这方面其实早就有开源项目了,例如memcached-session-manager(目前我们的官方商城都是使用这个),以及tomcat-redis-session-manager。
不过这种方式有个缺点,就是需要耦合Tomcat/Jetty等Servlet容器的代码。

2.设计一个Filter,利用HttpServletRequestWrapper,实现自己的 getSession()方法,接管创建和管理Session数据的工作。spring-session就是通过这样的思路实现的。

3.与其自己写方法实现造*,不如直接使用*spring session。

spring session简介

spring-session是spring旗下的一个项目,把servlet容器实现的httpSession替换为spring-session,专注于解决 session管理问题。可简单快速且无缝的集成到我们的应用中。

特性

1.轻易把session存储到第三方存储容器,框架提供了redis、jvm的map、mongo、gemfire、hazelcast、jdbc等多种存储session的容器的方式。

2.同一个浏览器同一个网站,支持多个session问题。

3.Restful API,不依赖于cookie。可通过header来传递jessionID

4.WebSocket和spring-session结合,同步生命周期管理。

spring session原理

spring-session无缝替换应用服务器的request大概原理是:

1.自定义个Filter,实现doFilter方法

2.继承 HttpServletRequestWrapper 、HttpServletResponseWrapper 类,重写getSession等相关方法(在这些方法里调用相关的 session存储容器操作类)。

3.在 第一步的doFilter中,new 第二步 自定义的request和response的类。并把它们分别传递 到 过滤器链

4.把该filter配置到 过滤器链的第一个位置上

有兴趣研究源码的,可以看看这篇文章:
http://www.infoq.com/cn/articles/Next-Generation-Session-Management-with-Spring-Session

spring session和mongoDB整合使用

使用起来非常简单,只需四步,我们就能像以前一样使用session了。

第一步:新建一个spring boot项目。

第二步:添加依赖

<!-- mongoDB相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- spring session相关依赖 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

第三步:在application.yml配置文件中添加配置

#mongoDB服务相关配置
spring:
data:
mongodb:
host: localhost
port: 27017
database: mydb

第四步:添加一个配置类

@Configuration
@EnableMongoHttpSession
public class HttpSessionConfig {
@Bean
public JdkMongoSessionConverter jdkMongoSessionConverter() {
return new JdkMongoSessionConverter();
}

@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
return serializer;
}
}

这样就能使用分布式session了,可以说灰常简单了!!!

参考文章