使用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

相關文章
相關標籤/搜索