使用springboot+springsession实现分布式session以及源码解析
接上问springboot使用redis
springsession是什么
实现分布式session管理
为什么要使用springsession
spring全家桶,不想自己实现分布式session管理可以使用
添加依赖
org.springframework.session
spring-session
添加配置
@EnableRedisHttpSession
public class HttpSessionConfiguration {
}
测试
原理分析
SpringHttpSession
第一步查看@EnableRedisHttpSession
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ java.lang.annotation.ElementType.TYPE })
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration
public @interface EnableRedisHttpSession {
...
}
进二步查看RedisHttpSessionConfiguration
@Configuration
@EnableScheduling
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements EmbeddedValueResolverAware, ImportAware {
...
}
第三步发现其集成自SpringHttpSessionConfiguration查看
public class SpringHttpSessionConfiguration implements ApplicationContextAware {
private CookieHttpSessionStrategy defaultHttpSessionStrategy = new CookieHttpSessionStrategy();
private boolean usesSpringSessionRememberMeServices;
private ServletContext servletContext;
private CookieSerializer cookieSerializer;
private HttpSessionStrategy httpSessionStrategy = this.defaultHttpSessionStrategy;
private List httpSessionListeners = new ArrayList();
@PostConstruct
public void init() {
if (this.cookieSerializer != null) {
this.defaultHttpSessionStrategy.setCookieSerializer(this.cookieSerializer);
}
else if (this.usesSpringSessionRememberMeServices) {
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setRememberMeRequestAttribute(
SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);
this.defaultHttpSessionStrategy.setCookieSerializer(cookieSerializer);
}
}
@Bean
public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() {
return new SessionEventHttpSessionListenerAdapter(this.httpSessionListeners);
}
@Bean
public SessionRepositoryFilter extends ExpiringSession> springSessionRepositoryFilter(
SessionRepository sessionRepository) {
SessionRepositoryFilter sessionRepositoryFilter = new SessionRepositoryFilter(
sessionRepository);
sessionRepositoryFilter.setServletContext(this.servletContext);
if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy(
(MultiHttpSessionStrategy) this.httpSessionStrategy);
}
else {
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
}
return sessionRepositoryFilter;
}
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
if (ClassUtils.isPresent(
"org.springframework.security.web.authentication.RememberMeServices",
null)) {
this.usesSpringSessionRememberMeServices = !ObjectUtils
.isEmpty(applicationContext
.getBeanNamesForType(SpringSessionRememberMeServices.class));
}
}
@Autowired(required = false)
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
@Autowired(required = false)
public void setCookieSerializer(CookieSerializer cookieSerializer) {
this.cookieSerializer = cookieSerializer;
}
@Autowired(required = false)
public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
this.httpSessionStrategy = httpSessionStrategy;
}
@Autowired(required = false)
public void setHttpSessionListeners(List listeners) {
this.httpSessionListeners = listeners;
}
}
发现其session默认的策略是使用
defaultHttpSessionStrategy=new CookieHttpSessionStrategy();cookie来实现
继续看
@Bean
public SessionRepositoryFilter extends ExpiringSession> springSessionRepositoryFilter(
SessionRepository sessionRepository) {
SessionRepositoryFilter sessionRepositoryFilter = new SessionRepositoryFilter(
sessionRepository);
sessionRepositoryFilter.setServletContext(this.servletContext);
if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) {
sessionRepositoryFilter.setHttpSessionStrategy(
(MultiHttpSessionStrategy) this.httpSessionStrategy);
}
else {
sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy);
}
return sessionRepositoryFilter;
}
传入参数SessionRepository的实现类RedisOperationsSessionRepository在RedisHttpSessionConfiguration被进行创建所以sessionRepository使用的就是RedisOperationsSessionRepository用来做于存储
继续查看SessionRepositoryFilter
public class SessionRepositoryFilter
extends OncePerRequestFilter {
...
}
继承自OncePerRequestFilter
abstract class OncePerRequestFilter implements Filter {
public final void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
调用doFilterInternal由SessionRepositoryFilter实现
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(
request, response, this.servletContext);
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(
wrappedRequest, response);
HttpServletRequest strategyRequest = this.httpSessionStrategy
.wrapRequest(wrappedRequest, wrappedResponse);
HttpServletResponse strategyResponse = this.httpSessionStrategy
.wrapResponse(wrappedRequest, wrappedResponse);
try {
filterChain.doFilter(strategyRequest, strategyResponse);
}
finally {
wrappedRequest.commitSession();
}
}
包装请求,响应对象
根据策略处理包装请求对象
最后wrappedRequest.commitSession();
HttpSessionWrapper wrappedSession = getCurrentSession();
if (wrappedSession == null) {
if (isInvalidateClientSession()) {
SessionRepositoryFilter.this.httpSessionStrategy
.onInvalidateSession(this, this.response);
}
}
else {
S session = wrappedSession.getSession();
SessionRepositoryFilter.this.sessionRepository.save(session);
if (!isRequestedSessionIdValid()
|| !session.getId().equals(getRequestedSessionId())) {
SessionRepositoryFilter.this.httpSessionStrategy.onNewSession(session,
this, this.response);
}
}
这就是最终处理,就不做详细解释了
几张图
SessionRepository的实现类
参考