侧边栏壁纸
  • 累计撰写 98 篇文章
  • 累计创建 85 个标签
  • 累计收到 9 条评论

spring Session核心原理分析

bearjun
2021-06-22 / 0 评论 / 2 点赞 / 1,218 阅读 / 4,095 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2021-06-22,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前言

前面已经介绍了几种常用的分布式session的解决方案,这次,我们来看看spring session的核心原理。

原理分析

@EnableRedisHttpSession注解

@Import(RedisHttpSessionConfiguration.class)
@Configuration(proxyBeanMethods = false)
public @interface EnableRedisHttpSession {
   .......
}

进入注解内部,可以看到。当前注解是一个配置文件,并且导入了RedisHttpSessionConfiguration的配置。

RedisHttpSessionConfiguration

@Configuration(proxyBeanMethods = false)
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
		implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware {

.........

@Bean
public RedisIndexedSessionRepository sessionRepository() {
	RedisTemplate<Object, Object> redisTemplate = createRedisTemplate();
	RedisIndexedSessionRepository sessionRepository = new RedisIndexedSessionRepository(redisTemplate);
	sessionRepository.setApplicationEventPublisher(this.applicationEventPublisher);
	if (this.indexResolver != null) {
		sessionRepository.setIndexResolver(this.indexResolver);
	}
	if (this.defaultRedisSerializer != null) {
		sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
	}
	sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
	if (StringUtils.hasText(this.redisNamespace)) {
		sessionRepository.setRedisKeyNamespace(this.redisNamespace);
	}
	sessionRepository.setFlushMode(this.flushMode);
	sessionRepository.setSaveMode(this.saveMode);
	int database = resolveDatabase();
	sessionRepository.setDatabase(database);
	this.sessionRepositoryCustomizers
			.forEach((sessionRepositoryCustomizer) -> sessionRepositoryCustomizer.customize(sessionRepository));
	return sessionRepository;
}
  ...........

}
@Configuration(proxyBeanMethods = false)
public class SpringHttpSessionConfiguration implements ApplicationContextAware {
@PostConstruct
public void init() {
	CookieSerializer cookieSerializer = (this.cookieSerializer != null) ? this.cookieSerializer
			: createDefaultCookieSerializer();
	this.defaultHttpSessionIdResolver.setCookieSerializer(cookieSerializer);
}

@Bean
public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() {
	return new SessionEventHttpSessionListenerAdapter(this.httpSessionListeners);
}

@Bean
public <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(
		SessionRepository<S> sessionRepository) {
	SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(sessionRepository);
	sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);
	return sessionRepositoryFilter;
}

@Override
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));
	}
}
}
@Order(SessionRepositoryFilter.DEFAULT_ORDER)
public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFilter {
public SessionRepositoryFilter(SessionRepository<S> sessionRepository) {
		if (sessionRepository == null) {
			throw new IllegalArgumentException("sessionRepository cannot be null");
		}
		this.sessionRepository = sessionRepository;
	}

@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);
	SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,
			response);

	try {
		filterChain.doFilter(wrappedRequest, wrappedResponse);
	}
	finally {
		wrappedRequest.commitSession();
	}
}

}
  • 首先给容器放入一个组件,RedisIndexedSessionRepository,(其就是:sessionRepository) :redis操作sesion的增删改查
  • 实现SpringHttpSessionConfiguration给容器放入SessionRepositoryFilter组件,往底层深入,发现其就是Filter,每个请求必须经过Filter。
  • SessionRepositoryFilter的构造方法会传入sessionRepository。也就是创建的时候,会自动从容器中获取sessionRepository。
  • doFilterInternal方法把原生的request,response封装成了wrappedRequest,wrappedResponse。
  • 原本通过request.getSession()的,通过包装,其实都是wrappedRequest.getSession()获取的。
  • 而wrappedRequest.getSession()底层正是通过sessionRepository获取到的。

这是典型的:装饰者模式

2

评论区