SpringSession如何管理Session
SpringSession有一套独立的session模型,它和Servlet非常相似,最大的区别是session存放的位置,从StandardManger换到了SessionRepository。通过扩展SessionRepository,可以实现自定义session存储方式。下图是SpringSession和Servlet的session结构的对比:
SpringSession通过注册成Servlet Filter来拦截请求,将请求里注入自己的Session对象,实现session的管理。下面分析一下SpringSession是如何注册Filter和实现SessionRepository扩展的。
注册Filter
SpringSession要注册的Filter类型是SessionRepositoryFilter,它通过ServletContextInitializer 机制在web服务启动时注册Filter。SpringBoot为SpringSession自动装配了ServletContextInitializer。
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(SessionRepositoryFilter.class)
@EnableConfigurationProperties(SessionProperties.class)
class SessionRepositoryFilterConfiguration {@BeanFilterRegistrationBean> sessionRepositoryFilterRegistration(SessionProperties sessionProperties, SessionRepositoryFilter> filter) {FilterRegistrationBean> registration = new FilterRegistrationBean<>(filter);registration.setDispatcherTypes(getDispatcherTypes(sessionProperties));registration.setOrder(sessionProperties.getServlet().getFilterOrder());return registration;}
}
SessionRepositoryFilter对象是在SpringHttpSessionConfiguration 中注册成Bean,可以通过注解@EnableSpringHttpSession 来开启配置。
@Bean
public SessionRepositoryFilter extends Session> springSessionRepositoryFilter(SessionRepository sessionRepository) {SessionRepositoryFilter sessionRepositoryFilter = new SessionRepositoryFilter<>(sessionRepository);sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);return sessionRepositoryFilter;
}
在初始化SessionRepositoryFilter的时候,依赖SessionRepository 对象,需要我们传进来。这也是
SessionRepository扩展的实现,通过传入不同SessionRepository,实现session存到不同的介质。
@Bean
public SessionRepository sessionRepository() {return new MapSessionRepository(new ConcurrentHashMap());
}
至此,SessionRepositoryFilter就注册到FilterChain上了。在请求进来的时候,SessionRepositoryFilter将request和response包装成SessionRepositoryRequestWrapper 和SessionRepositoryResponseWrapper 类型的对象。后面的Filter从request操作session时,都会被SessionRepositoryRequestWrapper拦截,包括创建session。
创建session
SessionRepositoryRequestWrapper 覆盖了HttpSessionWrapper getSession(boolean create) ,在需要的时候会通过SessionRepository 来创建session对象。
@Override
public HttpSessionWrapper getSession(boolean create) {...S session = SessionRepositoryFilter.this.sessionRepository.createSession();session.setLastAccessedTime(Instant.now());currentSession = new HttpSessionWrapper(session, getServletContext());setCurrentSession(currentSession);return currentSession;
}
提交session时,也会把数据写回SessionRepository。
private void commitSession() {... SessionRepositoryFilter.this.sessionRepository.save(session);...
}
Session持久化到Redis
要把Session存到Redis,只要扩展SessionRepository,把session数据写入Redis。SpringSession为接入Redis提供了默认实现,核心只需两步配置:
引入spring-session-data-redis
org.springframework.session spring-session-data-redis
org.springframework.boot spring-boot-starter-data-redis
开启@EnableRedisHttpSession注解。如果使用了spring-boot就不用添加注解,会自动注册上去。
@EnableRedisHttpSession
@AutoConfiguration
public class AutoConfiguration {
}
标签:
相关文章
-
无相关信息