Springboot整合springsession实现session共享
简介
session我们之前有介绍过(可见springboot整合springsecurity),简单来说就是将用户信息或者数据存储在服务器上,通常用于验证用户身份或者避免通过获取相关信息。
但是,缺点也是非常明显:
-
占用服务器负载:我们可以使用
token,用时间换取空间 -
对于多服务器环境,
session无法共享
对于第二点缺点,我们目前有几种比较常用的解决方法
-
使用
cookie加密的方式将session保存在客户端上优点是可以减轻服务器压力,缺点是每次请求都要带上
cookie信息,占用一定带宽。此外若用户禁用cookie则无法使用 -
服务器间同步
通过配置
tomcat集群,在集群中广播自己的session信息,但是缺点很明显,当集群规模较大时,会占用大量资源来进行session同步处理 -
基于分布式缓存的
session共享机制将
session缓存到redis中,这样不同服务器都可以直接到内存中获取session,效率高,也最常用
Springsession
springSession是spring旗下的一个项目,把servlet容器实现的httpSession替换为springSession,专注于解决session管理问题。可简单快速且无缝的集成到我们的应用中。
springsession就是spring的一个框架,实现了我们上面说的基于分布式缓存的session共享机制
操作实例
我们先来看看简单的操作实例
pom.xml
<!-- springsession-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.5.1</version>
</dependency>
application.yml
spring:
redis:
# 数据库索引,默认为0
database: 0
# redis host ip
host: 192.168.56.129
# redis 连接端口
port: 6379
# 服务器连接密码(默认为空)
password:
# 连接超时时间(毫秒)
timeout: 1000
#设置springsession存储类型,默认为redis
session:
store-type: redis
启动类加上@EnableRedisHttpSession
@SpringBootApplication
@EnableRedisHttpSession
public class SpringsessionApplication {
public static void main(String[] args) {
SpringApplication.run(SpringsessionApplication.class, args);
}
}
SessionController
这里我们构建一个简单的controller测试是否实现了session共享
@RestController
@RequestMapping("/session")
public class SessionController {
/**
* 设置session
* @param request
* @param attributes
* @return
*/
@PostMapping("/set")
public Map<String,Object> setSession(HttpServletRequest request, @RequestParam("attributes")String attributes){
request.getSession().setAttribute("attributes",attributes);
Map<String,Object> map = new HashMap<String,Object>();
map.put("SessionID:",request.getSession().getId());
return map;
}
/**
* 获取session
* @param request
* @return
*/
@GetMapping("/get")
public String getSession(HttpServletRequest request){
String attributes = (String) request.getSession().getAttribute("attributes");
return attributes;
}
}
两个方法都很简单
setSession:通过请求中的参数设置session中的attributes
getSession:测试是否能获取在其他端口设定的session中对应attributes的值
运行结果
由于要体现session共享,所以我们这里将在两个不同端口运行程序
通过
IDEA不同端口启用同一个项目,可以在右上角运行处选择edit config,然后添加springboot项目,并同意parallel run
port:8080 /session/set
可以看到成功设置了session并且返回了SessionID
port:8090 /session/get
成功获取到了session中的值,标明我们实现了session共享
我们再来看看redis存储的session

这里以sessionID为KEY,session为value存储,但是sessionID前面的命名空间太长了,而且不具有项目标识,我们可以通过在application.yml中设置namespace="xx"即可
Springsession 逻辑分析
我们可以看到springsession使用非常简单,对于用户几乎不用进行什么操作,那么springsession具体为我们做了什么工作呢?
其实springsession通过autoconfigure帮我们自动配置了一个过滤器SessionRepositoryFitlter
SessionRepositoryFitlter
@Order(-2147483598)
public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFilter {
定义来看:
-
这里为
SessionRepositoryFilter设定了一个非常小的order值,以确保能够在filterchain中被优先执行。优先执行是为了将原生
HttpRequest进行替换和封装 -
继承了
OncePerRequestFilter,确保一次请求只通过一次
源码命名太长,直接贴代码太乱了,这里就直接截图了

可以看到,我们这里首先对request和response进行封装,之后将封装请求传入doFilter()
所以具体逻辑就在两个封装类中,这里我们着重关注request的封装类


获取session的逻辑如下:
-
this.getCurrentSession()检查serlvet容器中是否有session,如果有session则直接返回,如果没有则去redis中去拿 -
this.getRequestedSession()根据请求中的信息获取sessionID,然后根据sessionID去redis中获取session
这里并不是每次查询都是去
redis中查询,而是设置了一个session缓存,每次查询先检查缓存中有没有,如果有则直接拿值,如果没有则通过httpSessionIdResolver.resolveSessionIds(this)获取sessionID获取
sessionid有两种方式,一种是根据请求中Header信息获取,一种是放在cookie中我们这里
httpSessionIdResolver = new CookieHttpSessionIdResolver()选择使用cookie获取sessionID查询到
session之后,更新session相关信息并返回 -
如果在
redis中没有找到,则根据create判断是否创建新的session
基本的逻辑非常清楚也非常好理解,我们再来具体看看springsession是如何在redis中查询session的
SessionRepository
springsession为我们提供了这样一个session仓库,能够完成对session的CRUD操作
我们这里使用的是RedisSessionRepository,实现了将session存储在redis上的CRUD操作

这就是我们getRequestedSession()中使用的findById()
可以看到里面就是对redis数据库的直接操作
总结
本文主要介绍了springboot如何整合springsession实现session共享,也简单介绍了其中逻辑原理,具体的部分还是建议仔细阅读源码。
redis上的CRUD操作
[外链图片转存中…(img-guh79ZOd-1624583023491)]
这就是我们getRequestedSession()中使用的findById()
可以看到里面就是对redis数据库的直接操作
总结
本文主要介绍了springboot如何整合springsession实现session共享,也简单介绍了其中逻辑原理,具体的部分还是建议仔细阅读源码。
SpringBoot整合SpringSession
本文介绍如何使用SpringBoot结合SpringSession实现session共享,利用Redis作为分布式缓存存储session,解决了多服务器环境下session无法共享的问题。
797

被折叠的 条评论
为什么被折叠?



