美文网首页
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