springsession源码分析二之RedisHttpSessionConfiguration

SpringHttpSessionConfiguration

  1. SpringHttpSessionConfiguration是RedisHttpSessionConfiguration的父类
  2. 代码

    @Configuration
    public class SpringHttpSessionConfiguration {
    
        private CookieHttpSessionStrategy defaultHttpSessionStrategy = new CookieHttpSessionStrategy();
    
        private HttpSessionStrategy httpSessionStrategy = this.defaultHttpSessionStrategy;
    
        private List<HttpSessionListener> httpSessionListeners = new ArrayList<HttpSessionListener>();
    
        private ServletContext servletContext;
    
        @Bean
        public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() {
            return new SessionEventHttpSessionListenerAdapter(this.httpSessionListeners);
        }
        /***
        SessionRepositoryFilter的Bean是在这里被注入的
        **/
        @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;
        }
    
        @Autowired(required = false)
        public void setServletContext(ServletContext servletContext) {
            this.servletContext = servletContext;
        }
    
        @Autowired(required = false)
        public void setCookieSerializer(CookieSerializer cookieSerializer) {
            this.defaultHttpSessionStrategy.setCookieSerializer(cookieSerializer);
        }
    
        @Autowired(required = false)
        public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) {
            this.httpSessionStrategy = httpSessionStrategy;
        }
    
        @Autowired(required = false)
        public void setHttpSessionListeners(List<HttpSessionListener> listeners) {
            this.httpSessionListeners = listeners;
        }
    }

RedisHttpSessionConfiguration

  1. 代码

            /**
            0.RedisHttpSessionConfiguration 是一个编程式注解
            1. @Configuration相当于xml中的<beans>标签,使用AnnotationConfigApplicationContext读取配置
            而xml使用ClassPathXmlApplicationContext读取
            2. @EnableScheduling使用该注解让Spring可以进行任务调度,功能类似于Spring的xml命名空间<task:*>
            */
            @Configuration
            @EnableScheduling
            public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
                    implements ImportAware {
                //redis键的超时时间,即session,key的超时时间 
                private Integer maxInactiveIntervalInSeconds = 1800;
                /***
                *在Redis 2.8.0版本起,加入了“Keyspace notifications”(即“键空间通知”)的功能
                键空间通知,允许Redis客户端从“发布/订阅”通道中建立订阅关系,以便客户端能够在Redis中的数据因某种方式受到影响时收到相应事件
                在官方文档中,keyevent通道的格式永远是这样的:
            __keyevent@<db>__:prefix
            对于数据过期事件,我们在绑定订阅时通配模板也可以精确地写成:
            __keyevent@*__:expired
                **/
                private ConfigureRedisAction configureRedisAction = new ConfigureNotifyKeyspaceEventsAction();
                //redis key的命名空间 spring:session:<redisNamespace>
                private String redisNamespace = "";
                /**
                *ON_SAVE  当调用SessionRepository.save时候才被调用,web环境下就是响应提交的时候(默认)
                IMMEDIATE 当创建SessionRepository.createSession() 的时候或者给session设置属性的时候立即存入redis
                *ON_SAVE Only writes to Redis when SessionRepository.save(org.springframework.session.Session) is invoked. In a web environment this is typically done as soon as the HTTP response is committed.
                IMMEDIATE Writes to Redis as soon as possible. For example SessionRepository.createSession() will write the session to Redis. Another example is that setting an attribute on the session will also write to Redis immediately.
                **/
                private RedisFlushMode redisFlushMode = RedisFlushMode.ON_SAVE;
                //序列化方式
                private RedisSerializer<Object> defaultRedisSerializer;
    
                private Executor redisTaskExecutor;
    
                private Executor redisSubscriptionExecutor;
    
                /**
                RedisMessageListenerContainer 表示消息监听容器
                **/
                @Bean
                public RedisMessageListenerContainer redisMessageListenerContainer(
                        RedisConnectionFactory connectionFactory,
                        RedisOperationsSessionRepository messageListener) {
    
                    RedisMessageListenerContainer container = new RedisMessageListenerContainer();
                    container.setConnectionFactory(connectionFactory);
                    if (this.redisTaskExecutor != null) {
                        container.setTaskExecutor(this.redisTaskExecutor);
                    }
                    if (this.redisSubscriptionExecutor != null) {
                        container.setSubscriptionExecutor(this.redisSubscriptionExecutor);
                    }
                    /***
                    设置监听器与发布主题,主题名称为 __keyevent@*:del  __keyevent@*:expired
                    ***/
                    container.addMessageListener(messageListener,
                            Arrays.asList(new PatternTopic("__keyevent@*:del"),
                                    new PatternTopic("__keyevent@*:expired")));
                    /***
                    * this.keyPrefix + "event:created:"+ "*";
                    **/
                    container.addMessageListener(messageListener, Arrays.asList(new PatternTopic(
                            messageListener.getSessionCreatedChannelPrefix() + "*")));
                    return container;
                }
    
                @Bean
                public RedisTemplate<Object, Object> sessionRedisTemplate(
                        RedisConnectionFactory connectionFactory) {
                    RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
                    template.setKeySerializer(new StringRedisSerializer());
                    template.setHashKeySerializer(new StringRedisSerializer());
                    if (this.defaultRedisSerializer != null) {
                        template.setDefaultSerializer(this.defaultRedisSerializer);
                    }
                    template.setConnectionFactory(connectionFactory);
                    return template;
                }
    
                @Bean
                public RedisOperationsSessionRepository sessionRepository(
                        @Qualifier("sessionRedisTemplate") RedisOperations<Object, Object> sessionRedisTemplate,
                        ApplicationEventPublisher applicationEventPublisher) {
                    RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(
                            sessionRedisTemplate);
                    sessionRepository.setApplicationEventPublisher(applicationEventPublisher);
                    sessionRepository
                            .setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
                    if (this.defaultRedisSerializer != null) {
                        sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
                    }
    
                    String redisNamespace = getRedisNamespace();
                    if (StringUtils.hasText(redisNamespace)) {
                        sessionRepository.setRedisKeyNamespace(redisNamespace);
                    }
    
                    sessionRepository.setRedisFlushMode(this.redisFlushMode);
                    return sessionRepository;
                }
    
                public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
                    this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
                }
    
                public void setRedisNamespace(String namespace) {
                    this.redisNamespace = namespace;
                }
    
                public void setRedisFlushMode(RedisFlushMode redisFlushMode) {
                    Assert.notNull(redisFlushMode, "redisFlushMode cannot be null");
                    this.redisFlushMode = redisFlushMode;
                }
    
                private String getRedisNamespace() {
                    if (StringUtils.hasText(this.redisNamespace)) {
                        return this.redisNamespace;
                    }
                    return System.getProperty("spring.session.redis.namespace", "");
                }
    
                public void setImportMetadata(AnnotationMetadata importMetadata) {
    
                    Map<String, Object> enableAttrMap = importMetadata
                            .getAnnotationAttributes(EnableRedisHttpSession.class.getName());
                    AnnotationAttributes enableAttrs = AnnotationAttributes.fromMap(enableAttrMap);
                    this.maxInactiveIntervalInSeconds = enableAttrs
                            .getNumber("maxInactiveIntervalInSeconds");
                    this.redisNamespace = enableAttrs.getString("redisNamespace");
                    this.redisFlushMode = enableAttrs.getEnum("redisFlushMode");
                }
    
                @Bean
                public InitializingBean enableRedisKeyspaceNotificationsInitializer(
                        RedisConnectionFactory connectionFactory) {
                    return new EnableRedisKeyspaceNotificationsInitializer(connectionFactory,
                            this.configureRedisAction);
                }
    
                /**
                 * Sets the action to perform for configuring Redis.
                 *
                 * @param configureRedisAction the configureRedis to set. The default is
                 * {@link ConfigureNotifyKeyspaceEventsAction}.
                 */
                @Autowired(required = false)
                public void setConfigureRedisAction(ConfigureRedisAction configureRedisAction) {
                    this.configureRedisAction = configureRedisAction;
                }
                /**
                *如果需要覆盖默认的Redis序列化实现类,在spring中将自己的实现类id设置为  springSessionDefaultRedisSerializer
                **/
                @Autowired(required = false)
                @Qualifier("springSessionDefaultRedisSerializer")
                public void setDefaultRedisSerializer(
                        RedisSerializer<Object> defaultRedisSerializer) {
                    this.defaultRedisSerializer = defaultRedisSerializer;
                }
            /**
                *如果需要覆盖默认Redis任务多线程Executor,在spring中将自己的实现类id设置为springSessionRedisTaskExecutor
                **/
                @Autowired(required = false)
                @Qualifier("springSessionRedisTaskExecutor")
                public void setRedisTaskExecutor(Executor redisTaskExecutor) {
                    this.redisTaskExecutor = redisTaskExecutor;
                }
                /**
                *如果需要覆盖默认订阅任务多线程Executor,在spring中将自己的实现类id设置为   springSessionRedisSubscriptionExecutor
                **/
                @Autowired(required = false)
                @Qualifier("springSessionRedisSubscriptionExecutor")
                public void setRedisSubscriptionExecutor(Executor redisSubscriptionExecutor) {
                    this.redisSubscriptionExecutor = redisSubscriptionExecutor;
                }
    
                /**
                 * Ensures that Redis is configured to send keyspace notifications. This is important
                 * to ensure that expiration and deletion of sessions trigger SessionDestroyedEvents.
                 * Without the SessionDestroyedEvent resources may not get cleaned up properly. For
                 * example, the mapping of the Session to WebSocket connections may not get cleaned
                 * up.
                 */
                static class EnableRedisKeyspaceNotificationsInitializer implements InitializingBean {
                    private final RedisConnectionFactory connectionFactory;
    
                    private ConfigureRedisAction configure;
    
                    EnableRedisKeyspaceNotificationsInitializer(
                            RedisConnectionFactory connectionFactory,
                            ConfigureRedisAction configure) {
                        this.connectionFactory = connectionFactory;
                        this.configure = configure;
                    }
    
                    public void afterPropertiesSet() throws Exception {
                        RedisConnection connection = this.connectionFactory.getConnection();
                        this.configure.configure(connection);
                    }
                }
  2. 配置

            <bean id="redisHttpSessionConfiguration"
                class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
                <property name="maxInactiveIntervalInSeconds" value="${redis.session.time}" />
                <property name="redisNamespace" value="${redis.session.namespace}"/>
                <property name="cookieSerializer" ref="cookieSerializer" />
            </bean>
    
            <bean id="cookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
                <property name="domainName" value="${cookie.domain}" />
                <property name="cookiePath" value="/" />
                <property name="cookieName" value="${cookie.cookieName}" />
            </bean>

猜你喜欢

转载自blog.csdn.net/usagoole/article/details/80639804