目录
一 分布式session
为什么要使用分布式session,传统的session有什么局限性吗?
这一切都得从分布式说起。
当服务使用分布式部署在服务器时,假设用户请求落在了服务器A上,用户拿到了对应的sessionId,用户再次请求服务时,落在了服务器B上,服务器B不认识sessionId,用户上一次的信息便无法同步了。
解决方法
1. 粘连性
通过negix设置负载均衡,使同一个用户只会访问同一台服务器。
缺点不符合分布式
2. 同步session
各个服务器之间同步session
缺点同步需要时间,消耗比较大
3.集中管理
将session统一存储在一个服务器上,一般会使用redis等高性能服务器
springsession就是用这种方式
二 如何使用
spring-session 定义了一个过滤器,会拦截传入的session,并并将出入的信息存储在Redis中,取session中的数据也会在Redis中取
引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies>
配置redis
spring:
application:
name: spring-session
redis:
host: 42.192.129.221
port: 6379
password: f254438
database: 0
timeout: 0
jedis:
pool:
max-active: 3
max-idle: 8
min-idle: 0
SpringSession配置类及其启动类
@EnableRedisHttpSession()
@Configuration
public class SessionConfig {
@Bean(name = "springSessionDefaultRedisSerializer")
public RedisSerializer springSessionDefaultRedisSerializer(){
//使用高性能序列化
return RedisSerializer.json();
}
}
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
测试
@RestController
@RequestMapping("/session")
public class SessionController {
@RequestMapping("/set")
public void set(HttpSession httpSession, @RequestParam("key") String key, @RequestParam("value") String value){
httpSession.setAttribute(key,value);
}
@RequestMapping("getAll")
public Map getAllSession(HttpSession httpSession){
HttpSessionIdResolver
HashMap<String, Object> map = new HashMap<>();
for (Enumeration<String> attributeNames = httpSession.getAttributeNames(); attributeNames.hasMoreElements();){
String key = attributeNames.nextElement();
Object value = httpSession.getAttribute(key);
map.put(key,value);
}
return map;
}
}
设置set key为name value为feng
redis中
三 源码
1.SessionRepositoryFilter
原理,将HttpServletRquest封装成RequestWrapper,HttpServletRquest.getSession时会调用RequestWrapper的SessionWrapper对象。
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//访问外部数据源的操作类 如redis MNONGDB等
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
request, response, this.servletContext);
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
wrappedRequest, response);
try {
filterChain.doFilter(wrappedRequest, wrappedResponse);
}
finally {
//请求结束提交session到外部数据源
wrappedRequest.commitSession();
}
}
拦截器会将HttpServletRequest包装成定义RequestWrapper对象同时把外部存储的操作类存储起来,当调用HttpServletRquest.getSession时就会调用定义的SessionWrapper对象了
2.EnableRedisHttpSession
开启自动化配置springSession,使用Redis作为数据源
maxInactiveIntervalInSeconds 不活跃后过期时间
redisNamespace rediskey的前缀 默认为spring:session
redisFlushMode 会话刷新模式 执行完统一写入还是每次都写入
cleanupCron 清除过期key的corn表达式
3.HttpSessionIdResolver
SessionId支持存储在cookies中或者header中
所以有两个实现类
HeaderHttpSessionIdResolver
CookieHttpSessionIdResolver
拓展
Session基本上不太用了
可以多了解了解Autho2和jwt