Spring Session
Spring Session的介绍
Spring Session 提供了用于管理用户会话信息的 API 和实现。它还提供与以下各项的透明集成:
HttpSession - 允许以应用程序容器(即 Tomcat)中立的方式替换 HttpSession。附加功能包括:
集群会话- Spring Session 使得支持集群会话变得微不足道,而无需绑定到特定于应用程序容
器的解决方案。
多个浏览器会话- Spring Session 支持在单个浏览器实例中管理多个用户的会话(即类似于
Google 的多个经过身份验证的帐户)。
RESTful APIs - Spring Session 允许在标头中提供会话 ID 以使用RESTful APIs
WebSocket - 提供 HttpSession 在接收 WebSocket 消息时保持活动的能力
Spring Session 是Spring家族中的一个子项目,它提供一组API和实现,用于管理用户的session信息
它把servlet容器实现的httpSession替换为spring-session,专注于解决 session管理问题,Session信
息存储在Redis中,可简单快速且无缝的集成到应用中。
官方地址:Spring Session
配置需求:
Spring Session 的最低要求是:
Java 8+。
如果您在 Servlet 容器(非必需)中运行,则为 Servlet 3.1+。
如果您使用其他 Spring 库(不是必需的),则所需的最低版本为 Spring 5.0.x。
Spring Session 上手操作
创建maven项目,选择web模板
修改POM.XML配置文件:
创建包
建立一个servlet,用于设置session.
SpringSession集成到WEB 项目当中
在pom.xml文件中,添加Spring Session相关的依赖
在web.xml文件中配置springSessionRepositoryFilter过滤器
在web.xml文件中加载Spring配置文件
创建applicationContext-session.xml
配置一个RedisHttpSessionConfiguration类 >:用于激活已经在Spring容器中注册的bean或者注解,
因为通过容器创建的bean中,底层有可能使用了其它的注解,通过>就不能指定具体的包,可以使用>
激活
配置Spring-data-redis
配置redis.properties文件
修改setSessionCTRL servlet中的代码:
加入另一个servlet ,名称为:GetServlet.java
部署测试:
edis.hostName=192.168.235.128
redis.port=6379
redis.password=123456
redis.usePool=true
redis.timeout=15000
protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
request.getSession().setAttribute(“myKey”,”springSession Data set”);
response.getWriter().println(“Set Session success !”);
} p
rotected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
// TODO Auto-generated method stub
String data= (String) request.getSession().getAttribute(“myKey”);
response.getWriter().println(data);
}
演示session的共享,我们这里配置两个tomcat服务器,端口号分别为9100和9200,将我们上面创建好
的项目分别部署到这两台服务器上。一台服务器执行放session,另一台服务器执行取session的操作
启动Linux node91上的Redis服务器:
缓存机制
每一个session,Redis实际缓存的数据如下:
spring:session:sessions:1b8b2340-da25-4ca6-864c-4af28f033327
spring:session:sessions:expires:1b8b2340-da25-4ca6-864c-4af28f033327
spring:session:expirations:1557389100000
spring:session:sessions为hash结构。
样例如下:
将springsession01项目分别在两台tomcat服务器上进行运行:
先运行第一台tomcat,对分布式的SpringSession进行设置的调用。
打开,Redis的客户端,可以看到,分布式的Session已经存在于redis服务器中。
在另一台tomcat上进行测试 ,对分布式的session进行取值操作:
总结:
Spring Session此处的作用是在分布式的多台Tomcat环境下,进行session的共享设置与读取。
在Tomcat8080的服务器下,进行了Spring session set工作。
在tomcat8081的服务器下,进行了spring session get工作。
中间的session 会话,在redis服务器中,进行上存储,通过RDM进行查询。
Spring boot 实现 Spring Session 分布式项目共享
Session
Http协议本身是无状态的,为了保存会话信息,浏览器Cookie通过SessionID标识会话请求,服务器以
SessionID为key来存储会话信息。在单实例应用中,可以考虑应用进程自身存储,随着应用体量的增
长,需要横向扩容,多实例Session共享问题随之而来。
在分布式的架构中,会出现无法获取到Session信息,不知道是哪个用户的请求。例如客户端发起一个
请求,这个请求到了Nginx之后,会被Nginx转发到 Tomcat A上,然后在Tomcat A上的Session存储数
据。后面又来一个请求,这个请求被Nginx转发到Tomcat B上,此时再去获取Session会发现没有数
据。对于这样的问题有一个主流的解决办法,就是用Spring session实现共享Session,把Session存储
到Reids里面。
这样无论存储还是读取Session的操作,都是去操作Redis中存储Session信息而不是自身内存中的
Session,其他Tomcat也是如此,这样就实现了Session 共享。
开发步骤
新建spring boot类型的项目
添加依赖支持
Application.properties中配置Redis连接信息:
建立MVC相关的包
建立Session Ctrl 控制器类:
redis 配置 ####
# 基本连接信息配置
spring.redis.database = 0
spring.redis.host = 192.168.122.100
spring.redis.port = 6379
spring.redis.password = 123456
# 连接池信息配置
spring.redis.jedis.pool.max-active = 8
spring.redis.jedis.pool.max-idle = 8
spring.redis.jedis.pool.max-wait = -1
spring.redis.jedis.pool.min-idle = 0
spring.redis.timeout = 0
在application.properties文件中,指定spring boot程序的端口号:
将springbootSession02项目指定在8085端口上,启动此springboot程序
在浏览器中进行访问,调用save/jeflee方法,对session进行设置。
package com.neu.mvc;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
@RestController
public class SessionController {
@Value(“${server.port}”)
String port;
@GetMapping(“/save/{name}”)
public String saveName(@PathVariable(“name”) String name, HttpSession
session) {
session.setAttribute(“name”, name);
return port;
} @
GetMapping(“/get”)
public String getName(HttpSession session) {
return port + “:” + session.getAttribute(“name”).toString();
}
}
可以看到,当调用save方法的时候,指定了一个分布式SESSION的value,名字为jeflee.
将springbootSession02项目进行复制,成为:springbootSession03_get
修改application.properties文件,将端口号改为8086,生成新的项目:
启动 springbootSession03_get 项目:
调用localhost:8086/get 方法,查看调用的端口号与返回值,此项返回值即为spring session存储在
redis服务器中的分布式返回值:jeflee.
同时,在redis服务器中,观察利用redis对spring session 进行存储的情况:
#### redis 配置 ####
# 基本连接信息配置
spring.redis.database = 0
spring.redis.host = 192.168.122.100
spring.redis.port = 6379
spring.redis.password = 123456
# 连接池信息配置
spring.redis.jedis.pool.max-active = 8
spring.redis.jedis.pool.max-idle = 8
spring.redis.jedis.pool.max-wait = -1
spring.redis.jedis.pool.min-idle = 0
spring.redis.timeout = 0
server.port=8086
Spring Session的执行流程(源码分析)
1.页面请求被全局的过滤器org.springframework.web.filter.DelegatingFilterProxy过滤 2.全局的过滤
器是一个代理过滤器,它不执行真正的过滤逻辑,它代理了一个Spring容器中的名为:
(springSessionRepositoryFilter) 的一个过滤器 3.代理的这个 springSessionRepositoryFilter 过滤器是
从spring容器中获取的,真正执行过滤逻辑的是 SessionRepositoryFilter @Bean注解 相当于:
4.该SessionRepositoryFilter过滤器覆盖了原来servlet中的request和response接口中定义的操作
session方法,替换成自己的session方法 5.在过滤的时候,总是会执行一个finally语句块,在finally中
提交session,保存到Redis session以hash结构存放在redis
6.默认的过期时间30分钟
总结
……..
tpSessionConfiguration”>
Spring Session给我们提供了很好的分布式环境下资源共享问题解决思路,其基于Servlet 规范实现,业
务使用时只需要简单配置就可以实现session共享,做到与业务低耦合,这是一线项目开发中可以借签
的设计理念。