环境:springboot2.3.9.RELEASE + Spring Session
引入相关依赖
<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>
</dependency>
应用配置文件
spring:
redis:
host: localhost
port: 16379
password: 111111
database: 4
lettuce:
pool:
maxActive: 8
maxIdle: 100
minIdle: 10
maxWait: -1
使用Redis来存储Session必须配置
RedisConnectionFactoryBean。由于这里我们redis-starter自动为我们配置了该Bean。
启用Redis存储Session
@SpringBootApplication
@EnableRedisHttpSession
public class SpringBootHttpsessionApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHttpsessionApplication.class, args);
}
}
使用@EnableRedisHttpSession开启功能。
Controller设置Session
@RestController
@RequestMapping("/sessions")
public class SessionController {
@Resource
private HttpServletRequest request ;
@GetMapping("/index")
public Object index() {
request.getSession().setAttribute("username", "asoklove") ;
return "set session success" ;
}
@GetMapping("/get")
public Object get() {
System.out.println(request.getSession()) ;
return request.getSession().getAttribute("username") ;
}
}
调用接口
session信息已经存储到了redis中;使用就是这么简单。
源码分析
进入@EnableRedisHttpSession类中
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration(proxyBeanMethods = false)
public @interface EnableRedisHttpSession {
}
@Import(RedisHttpSessionConfiguration.class)
进入
RedisHttpSessionConfiguration
@Autowired
public void setRedisConnectionFactory(
@SpringSessionRedisConnectionFactory ObjectProvider<RedisConnectionFactory> springSessionRedisConnectionFactory,
ObjectProvider<RedisConnectionFactory> redisConnectionFactory) {
RedisConnectionFactory redisConnectionFactoryToUse = springSessionRedisConnectionFactory.getIfAvailable();
if (redisConnectionFactoryToUse == null) {
redisConnectionFactoryToUse = redisConnectionFactory.getObject();
}
this.redisConnectionFactory = redisConnectionFactoryToUse;
}
这里就是要自动装配RedisConnectionFactory。
@Bean
public RedisIndexedSessionRepository sessionRepository() {
RedisTemplate<Object, Object> redisTemplate = createRedisTemplate();
RedisIndexedSessionRepository sessionRepository = new RedisIndexedSessionRepository(redisTemplate);
// ...
this.sessionRepositoryCustomizers
.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository));
return sessionRepository;
}
这里是配置SessionRepository Bean,该类是用来存储我们session的,通过类名
RedisIndexedSessionRepository也就知道了我们使用Redis进行存储。我们可以自定义SessionRepository来实现自己的Session存储类。
进入父类
SpringHttpSessionConfiguration中,这里配置了最核心的Filter
@Bean
public <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(
SessionRepository<S> sessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(sessionRepository);
sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);
return sessionRepositoryFilter;
}
该Filter Bean中配置了SessionRepository(这就是上面的
RedisIndexedSessionRepository);同时设置了session id解析器httpSessionIdResolver使用的默认的CookieHttpSessionIdResolver解析器,该类就是从header中的cookie中获取SESSION
第一次请求时,服务端会响应SESSION头信息
请求时Cookie携带信息:
这里我们也可以自定义HttpSessionIdResolver子类实现自己的解析器。比如可以读取Header中的其它信息来实现。
再接着说SessionRepositoryFilter过滤器,这个过滤的核心方法:
这里吧HttpServletRequest对象进行了包装
SessionRepositoryRequestWrapper
这个类非常重要;我们在代码中使用request.getSession()方法它都重写了
查看getSession(boolean)方法
HttpSession也被重写了,当我们在调用setAttribute时实际调用的是HttpSessionWrapper(父类)中的setAttribute,getAttribute方法。
在HttpSessionWrapper的父类中setAttribute方法
关键代码this.session.setAttribute(name, value);
这里的this.session就是一开始配置的
RedisIndexedSessionRepository 对象。
再回到过滤器的doFilterInternal方法。执行finally代码
这里的sessionRepository就是上面的的Bean。
这里的saveDelta方法开始存储session信息到redis中。
完毕!!!
给个关注+转发呗谢谢