使用springboot+springsession实现分布式session以及源码解析

使用springboot+springsession实现分布式session以及源码解析

接上问springboot使用redis

springsession是什么

实现分布式session管理html

为何要使用springsession

spring全家桶,不想本身实现分布式session管理能够使用html5

添加依赖

<dependency>
    <groupId>org.springframework.session</groupId>            
    <artifactId>spring-session</artifactId>
</dependency>

添加配置

@EnableRedisHttpSession
public class HttpSessionConfiguration {
	
}

测试

image image

原理分析

SpringHttpSessionjava

  • 第一步查看@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<HttpSessionListener> httpSessionListeners = new ArrayList<HttpSessionListener>();
	@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 <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(
			SessionRepository<S> sessionRepository) {
		SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(
				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<HttpSessionListener> listeners) {
		this.httpSessionListeners = listeners;
	}
}
发现其session默认的策略是使用
defaultHttpSessionStrategy=new CookieHttpSessionStrategy();cookie来实现
继续看
@Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(
		SessionRepository<S> sessionRepository) {
	SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(
			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<S extends ExpiringSession>
		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);
	}
}
这就是最终处理,就不作详细解释了

几张图

image

SessionRepository的实现类 imageweb

image

参考

springsessionredis

相关文章
相关标签/搜索