Redis存储Session启动顺序

2019-11-21  本文已影响0人  墨色尘埃

@EnableRedisHttpSession-注解 → 进入RedisHttpSessionConfiguration类

主要看RedisHttpSessionConfiguration类

image.png
  1. 该类实现ImportAware接口,所以先执行 setImportMetadata 方法
image.png
  1. 注入 RedisTemplate
image.png

当bean中需要注入其他参数或者引用时,将其作为方法的参数即可,Spring会帮你注入这些引用。这里RedisConnectionFactory被作为参数被注入进来

  1. 注入 RedisOperationsSessionRepository
    此方法的返回值是RedisOperationsSessionRepository,有关于session持久化到redis的相关操作都在此类中;
image.png

注:持久化到redis只是spring-session的一种方式,也支持持久化到其他数据库中(jdbc,Mongo,Hazelcast等)

3.1 注入父类的 SessionRepositoryFilter过滤器
所有的请求都会先经过SessionRepositoryFilter过滤器,doFilter方法如下:

image.png

request被包装成了SessionRepositoryRequestWrapper对象,response被包装成了SessionRepositoryResponseWrapper对象,SessionRepositoryRequestWrapper中重写了getSession等方法;finally中执行了commitSession方法,将session进行持久化操作;

3.2 注入父类的 SessionRepositoryRequestWrapper包装类
重点看一下重写的getSession方法,代码如下:

@Override
public HttpSessionWrapper getSession(boolean create) {
    // 从当前请求的attribute中获取session,如果有直接返回
    HttpSessionWrapper currentSession = getCurrentSession();
    if (currentSession != null) {
        return currentSession;
    }

    // 获取当前request的sessionId,这里使用了HttpSessionStrategy
    // 决定怎样将Request映射至Session,默认使用Cookie策略,即从cookies中解析sessionId
    String requestedSessionId = getRequestedSessionId();
    // 请求的如果sessionId存在且当前request的attribute中的没有session失效属性
    // 则根据sessionId获取spring session
    if (requestedSessionId != null
            && getAttribute(INVALID_SESSION_ID_ATTR) == null) {
        S session = getSession(requestedSessionId);
        // 如果spring session不为空,则将spring session包装成HttpSession并
        // 设置到当前Request的attribute中,防止同一个request getsession时频繁的到存储器
        //中获取session,提高性能
        if (session != null) {
            this.requestedSessionIdValid = true;
            currentSession = new HttpSessionWrapper(session, getServletContext());
            currentSession.setNew(false);
            setCurrentSession(currentSession);
            return currentSession;
        }
        // 如果根据sessionId,没有获取到session,则设置当前request属性,此sessionId无效
        // 同一个请求中获取session,直接返回无效
        else {
            // This is an invalid session id. No need to ask again if
            // request.getSession is invoked for the duration of this request
            if (SESSION_LOGGER.isDebugEnabled()) {
                SESSION_LOGGER.debug(
                        "No session found by id: Caching result for getSession(false) for this HttpServletRequest.");
            }
            setAttribute(INVALID_SESSION_ID_ATTR, "true");
        }
    }
    // 判断是否创建session
    if (!create) {
        return null;
    }
    if (SESSION_LOGGER.isDebugEnabled()) {
        SESSION_LOGGER.debug(
                "A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for "
                        + SESSION_LOGGER_NAME,
                new RuntimeException(
                        "For debugging purposes only (not an error)"));
    }
    // 根据sessionRepository创建spring session
    S session = SessionRepositoryFilter.this.sessionRepository.createSession();
    // 设置session的最新访问时间
    session.setLastAccessedTime(System.currentTimeMillis());
    // 包装成HttpSession透明化集成
    currentSession = new HttpSessionWrapper(session, getServletContext());
    // 设置session至Requset的attribute中,提高同一个request访问session的性能
    setCurrentSession(currentSession);
    return currentSession;
}

大致分为三步,① 首先去本地内存中获取session ② 如果获取不到去指定的数据库中获取,这里其实就是去redis里面获取,sessionRepository就是上面定义的RedisOperationsSessionRepository对象;③ 如果redis里面也没有则创建一个新的session;

  1. 注入 RedisMessageListenerContainer
image.png
  1. 注入 EnableRedisKeyspaceNotificationsInitializer
image.png
  1. 注入父类的 SessionEventHttpSessionListenerAdapter
image.png

RedisOperationsSessionRepository类,关于session的保存,更新,删除,获取操作都在此类中;

Spring-Session基于Redis管理Session

Spring Session的简单搭建与源码阅读

上一篇下一篇

猜你喜欢

热点阅读