美文网首页
Redis存储Session启动顺序

Redis存储Session启动顺序

作者: 墨色尘埃 | 来源:发表于2019-11-21 18:26 被阅读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的简单搭建与源码阅读

    相关文章

      网友评论

          本文标题:Redis存储Session启动顺序

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