1. 导入库文件
implementation 'org.springframework.session:spring-session-data-redis
于是org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
就生效了,
2 SessionAutoConfiguration
分析
里面有这个一段
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(SessionRepository.class)
@Import({ ServletSessionRepositoryImplementationValidator.class,
ServletSessionConfigurationImportSelector.class })
static class ServletSessionRepositoryConfiguration {
}
通过@import
引入了ServletSessionConfigurationImportSelector
,这个类继承SessionConfigurationImportSelector
static class ServletSessionConfigurationImportSelector extends SessionConfigurationImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return super.selectImports(WebApplicationType.SERVLET);
}
}
最终执行完后,会在SessionStoreMappings
的MAPPINGS
中找到RedisSessionConfiguration
并倒入到容器中
static {
Map<StoreType, Configurations> mappings = new EnumMap<>(StoreType.class);
mappings.put(StoreType.REDIS,
new Configurations(RedisSessionConfiguration.class, RedisReactiveSessionConfiguration.class));
mappings.put(StoreType.MONGODB,
new Configurations(MongoSessionConfiguration.class, MongoReactiveSessionConfiguration.class));
mappings.put(StoreType.JDBC, new Configurations(JdbcSessionConfiguration.class, null));
mappings.put(StoreType.HAZELCAST, new Configurations(HazelcastSessionConfiguration.class, null));
mappings.put(StoreType.NONE,
new Configurations(NoOpSessionConfiguration.class, NoOpReactiveSessionConfiguration.class));
MAPPINGS = Collections.unmodifiableMap(mappings);
}
3. RedisSessionConfiguration
作用分析
在RedisSessionConfiguration
中有一个静态内部类SpringBootRedisHttpSessionConfiguration
继承自RedisHttpSessionConfiguration
,RedisHttpSessionConfiguration
又继承了SpringHttpSessionConfiguration
类,
两个父类中注册了很多组建,关键就是RedisIndexedSessionRepository
和SessionRepositoryFilter
类。
@Configuration(proxyBeanMethods = false)
public static class SpringBootRedisHttpSessionConfiguration extends RedisHttpSessionConfiguration {
@Autowired
public void customize(SessionProperties sessionProperties, RedisSessionProperties redisSessionProperties,
ServerProperties serverProperties) {
Duration timeout = sessionProperties
.determineTimeout(() -> serverProperties.getServlet().getSession().getTimeout());
if (timeout != null) {
setMaxInactiveIntervalInSeconds((int) timeout.getSeconds());
}
setRedisNamespace(redisSessionProperties.getNamespace());
setFlushMode(redisSessionProperties.getFlushMode());
setSaveMode(redisSessionProperties.getSaveMode());
setCleanupCron(redisSessionProperties.getCleanupCron());
}
}
RedisHttpSessionConfiguration
中注册RedisIndexedSessionRepository
组件
@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;
}
RedisIndexedSessionRepository
用来生成、保存session。
SpringHttpSessionConfiguration
中注册SessionRepositoryFilter
SpringHttpSessionConfiguration
中注册SessionRepositoryFilter
组件
@Bean
public <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(
SessionRepository<S> sessionRepository) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<>(sessionRepository);
sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);
return sessionRepositoryFilter;
}
在SessionRepositoryFilterConfiguration
类中,有这样一段代码
@Bean
FilterRegistrationBean<SessionRepositoryFilter<?>> sessionRepositoryFilterRegistration(
SessionProperties sessionProperties, SessionRepositoryFilter<?> filter) {
FilterRegistrationBean<SessionRepositoryFilter<?>> registration = new FilterRegistrationBean<>(filter);
registration.setDispatcherTypes(getDispatcherTypes(sessionProperties));
registration.setOrder(sessionProperties.getServlet().getFilterOrder());
return registration;
}
最终将SessionRepositoryFilter
注册到servlet容器。这个SessionRepositoryFilter
类很关键,它将HttpServletRequest
包装成SessionRepositoryRequestWrapper,HttpServletResponse
包装成SessionRepositoryResponseWrapper
,SessionRepositoryRequestWrapper
中public HttpSessionWrapper getSession(boolean create)
,以后调用getSession等方法,就被拦截了,就会去RedisIndexedSessionRepository
中保存、生成session。
@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();
}
}
网友评论