一、Spring Session简介
spring全家桶之一,简单来说就是session + redis的组合,解决了在分布式系统下,不同模块之间session共享的问题。
二、Spring Session 原理
这是我们普通session的实现方案:
- 浏览器第一次登录把用户保存在服务器session里面,并且生成一个sessionid返回给浏览器
- 以后浏览器每一次访问都会带上这个sessionid,后端根据提交的sessionid取出用户信息,校验登录状态。
但是,在分布式系统下不同的服务、又或者相同的服务不同的集群如何共享这个session呢?
解决方法就是这个session,我们可以换一个地方存储,就不能在本地服务了,需要一个公共存放的地方、我们每一个服务都可以轻松访问。
使用DB或者Redis都是一个不错的选择,这个其实就是我们Spring Session实现的原理,如图:
三、Spring Session整合
1、导入依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置redis地址,指定类型为redis
spring:
redis:
host: 192.168.56.102
session:
store-type: redis
3、启动类上添加注解,全局启用
@EnableRedisHttpSession
public class WebApplication {
4、自定义配置类
@Configuration
public class SessionConfig {
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("HELLOSESSION");
serializer.setDomainName("hello.com");
return serializer;
}
}
- 由于默认使用jdk进行序列化,通过导入
RedisSerializer
修改为json序列化 - 通过修改
CookieSerializer
扩大session
的作用域至**.hello.com
5、SpringSession核心原理 - 装饰者模式
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
//对原生的request、response进行包装
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
request, response, this.servletContext);
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
wrappedRequest, response);
try {
filterChain.doFilter(wrappedRequest, wrappedResponse);
}
finally {
wrappedRequest.commitSession();
}
}
原生的获取session
时是通过HttpServletRequest
获取的,这里对request进行包装,并且重写了包装request的getSession()
方法。这样我们在项目里面使用spring session就跟使用本地session是一样的。