spring-session-redis

1 依赖
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session</artifactId>
    <version>${version.redis.session}</version>
</dependency>

 

2 使用注解启动spring基于redis的session管理
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600, redisNamespace = "sessionNamespace")
其中:sessionNamespace 会变成redis保存session的前缀;

此注解会导入:@Import({RedisHttpSessionConfiguration.class}),RedisHttpSessionConfiguration类会实现相应配置

3  配置RedisHttpSessionConfiguration类分析:

3.1 注册一个RedisOperationsSessionRepository bean到spring中,实现保存session到redis的功能

@Bean
public RedisOperationsSessionRepository sessionRepository(@Qualifier("sessionRedisTemplate") RedisOperations<Object, Object> sessionRedisTemplate, ApplicationEventPublisher applicationEventPublisher) {
        RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(sessionRedisTemplate);
        。。。。。。
        return sessionRepository;
}
当然redisTemplate也是配置了

@Bean
public RedisTemplate<Object, Object> sessionRedisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        if (this.defaultRedisSerializer != null) {
            // 使用默认的序列化器
            template.setDefaultSerializer(this.defaultRedisSerializer);
        }

        template.setConnectionFactory(connectionFactory);
        return template;

}

3.2 对SessionRepositoryFilter配置:
这个filter也会加入到ServletContext的过滤器执行器链中
RedisHttpSessionConfiguration的父类:SpringHttpSessionConfiguration注册了SessionRepositoryFilter的Bean到spring容器中

@Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
        // 向SessionRepositoryFilter设置了sessionRepository(实现类是RedisOperationsSessionRepository )
        // 所以最终filter的session操作落到redis上

        SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter(sessionRepository);
        sessionRepositoryFilter.setServletContext(this.servletContext);
        。。。。。

        return sessionRepositoryFilter;
    }

4 SessionRepositoryFilter类
由它来拦截url,实现session的操作

@Order(-2147483598)
public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerRequestFilter{

// 完成对redis session的操作
private final SessionRepository<S> sessionRepository;

。。。。。。

}

可以看到@Order(-2147483598)指定了一个非常大的负数,所以这个filter会在ServletContext比较前面的位置

filter的内部处理doFilterInternal方法:

 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  {
        request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository);
        SessionRepositoryFilter<S>.SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryFilter.SessionRepositoryRequestWrapper(request, response, this.servletContext);
        SessionRepositoryFilter<S>.SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryFilter.SessionRepositoryResponseWrapper(wrappedRequest, response);
        
        try {
            // 使用Wrapper完成正常的请求
            filterChain.doFilter(strategyRequest, strategyResponse);
        } finally {
            // 这个finally块会对session进行保存、更新等操作
            wrappedRequest.commitSession();

        }

    }
父类OncePerRequestFilter实现Filter接口的doFilter

public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) {
      。。。。。。
      //   调用子类实现doFilterInternal,这里是实现了filter的标准接口
      this.doFilterInternal(httpRequest, httpResponse, filterChain);

      。。。。。。
}

再来分析session是如何保存的,SessionRepositoryRequestWrapper内部类:

private final class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {
。。。。。。
 private void commitSession() {
            SessionRepositoryFilter<S>.SessionRepositoryRequestWrapper.HttpSessionWrapper wrappedSession = this.getCurrentSession();
            if (wrappedSession == null) {
                if (this.isInvalidateClientSession()) {
                    SessionRepositoryFilter.this.httpSessionStrategy.onInvalidateSession(this, this.response);
                }
            } else {
                // 保存redis的session中了
                S session = wrappedSession.getSession();
                SessionRepositoryFilter.this.sessionRepository.save(session);// 关注save方法
               。。。。。。
            }

        }
}

第一请进来,就会走else分支,保存或者更新session

 

下面分析sessionRepository.save(session)方法:

RedisOperationsSessionRepository类

 public void save(RedisOperationsSessionRepository.RedisSession session) {
        session.saveDelta();
        if (session.isNew()) {
            String sessionCreatedKey = this.getSessionCreatedChannel(session.getId());
            this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
            session.setNew(false);
        }

    }

 private void saveDelta() {
     。。。。。。
     String sessionId = this.getId();
     // 这里把session写到了redis中
     RedisOperationsSessionRepository.this.getSessionBoundHashOperations(sessionId).putAll(this.delta);

    。。。。。。
}

获取session方法
public RedisOperationsSessionRepository.RedisSession getSession(String id) {
    return this.getSession(id, false);
 }

private RedisOperationsSessionRepository.RedisSession getSession(String id, boolean allowExpired) {
       //  底层就是从redis中读取的session
        Map<Object, Object> entries = this.getSessionBoundHashOperations(id).entries();
        。。。。。。
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值