美文网首页
spring-session-data-redis自动配置原理

spring-session-data-redis自动配置原理

作者: Shinegalaxy | 来源:发表于2022-12-30 09:40 被阅读0次

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);
        }

    }

最终执行完后,会在SessionStoreMappingsMAPPINGS中找到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类,
两个父类中注册了很多组建,关键就是RedisIndexedSessionRepositorySessionRepositoryFilter类。

    @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,SessionRepositoryRequestWrapperpublic 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();
        }
    }

相关文章

网友评论

      本文标题:spring-session-data-redis自动配置原理

      本文链接:https://www.haomeiwen.com/subject/noexcdtx.html