• Spring Session 学习记录1


    先写些废话

      新公司项目是有用到redis,之前老公司使用的缓存框架是ehcache.我redis并不熟悉.看过介绍以后知道是个nosql..既然是个数据库,那我想操作方法和jdbc操作关系数据库应该差不多吧..百度了一些例子以后发现确实差不多...比如注入一个spring的template以后使用template就行了. 比如:

      很好理解,使用也蛮简单..就像jdbcTemplate...

      一次偶然的调试,我发现了一个有趣的地方(公司用的是自己的框架,封装了springboot...所以启动默认配置了什么bean,很难看出来...)...

    我记得session在tomcat启动服务器的时候好像是XXXSessionFacade..这里却是和Redis相关的一个实现类..然后向这个session存进去的东西再redis里也可以找到.

    这说明这个session数据存取都是向redis去操作的.

    看来一下maven的POM文件发现公司的项目依赖于srping-session-data-redis这个框架.

    Spring整合SpringSession

    实验了一下,发现其实spring只要额外配置2个bean就可以集成springsession了.

        <context:annotation-config />
         <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        </bean> 
    
        <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
            <property name="hostName" value="10.86.87.173" />
            <property name="password" value="mesRedis+)" />
        </bean>

    稍微研究了下发现JedisConnectionFactory这个bean就是配置了Spring怎么通过jedis去连接redis服务器.

    RedisHttpSessionConfiguration这个bean是真正和session相关的,它本身类上有注解@Configuration和@EnableScheduling.

    @Configuration配合它方法上的@Bean可以配置一些其他的bean,比如SessionRepositoryFilter 就配置了一个bean,对应web.xmlXML里配置的那个filter...

    @EnableScheduling这个注解我没用过,估计是要定时做一些事情,比如session过期了要去redis删除数据吧(但是redis好像也有超时删除数据的功能,为啥还要这么做呢..redis和Springsession都是第一次用,不太了解)..

    除了上面2个bean,只要在web.xml里配置一个filter就行了.

    1     <filter>
    2         <filter-name>springSessionRepositoryFilter</filter-name>
    3         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    4     </filter>
    5     <filter-mapping>
    6         <filter-name>springSessionRepositoryFilter</filter-name>
    7         <url-pattern>/*</url-pattern>
    8     </filter-mapping>

    原理

    因为第一次用,很多代码都没看过,所以不一定对.我觉得原理是这样的:

    1.RedisHttpSessionConfiguration里会配置一个filter

        @Bean
        public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository, ServletContext servletContext) {
            SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
            sessionRepositoryFilter.setServletContext(servletContext);
            if(httpSessionStrategy != null) {
                sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
            }
            return sessionRepositoryFilter;
        }

    注入一个sessionRepository.这个repository其实就是redis的repository.只是哪里生成的我并不知道...

        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            request.setAttribute(SESSION_REPOSITORY_ATTR, sessionRepository);
    
            SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response, servletContext);
            SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,response);
    
            HttpServletRequest strategyRequest = httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);
            HttpServletResponse strategyResponse = httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse);
    
            try {
                filterChain.doFilter(strategyRequest, strategyResponse);
            } finally {
                wrappedRequest.commitSession();
            }
        }

    这个filter会把request和response外面包装一层,就是装饰着模式.当调用request的getSession的时候

            @Override
            public HttpSession getSession(boolean create) {
                HttpSessionWrapper currentSession = getCurrentSession();
                if(currentSession != null) {
                    return currentSession;
                }
                String requestedSessionId = getRequestedSessionId();
                if(requestedSessionId != null) {
                    S session = sessionRepository.getSession(requestedSessionId);
                    if(session != null) {
                        this.requestedSessionIdValid = true;
                        currentSession = new HttpSessionWrapper(session, getServletContext());
                        currentSession.setNew(false);
                        setCurrentSession(currentSession);
                        return currentSession;
                    }
                }
                if(!create) {
                    return null;
                }
                S session = sessionRepository.createSession();
                currentSession = new HttpSessionWrapper(session, getServletContext());
                setCurrentSession(currentSession);
                return currentSession;
            }

    其实是从sessionRepository里去拿session的.所以我们使用的HttpSession的实现类应该是 HttpSessionWrapper 里面包裹着 RedisSession.

     1     private RedisSession getSession(String id, boolean allowExpired) {
     2         Map<Object, Object> entries = getSessionBoundHashOperations(id).entries();
     3         if(entries.isEmpty()) {
     4             return null;
     5         }
     6         MapSession loaded = new MapSession();
     7         loaded.setId(id);
     8         for(Map.Entry<Object,Object> entry : entries.entrySet()) {
     9             String key = (String) entry.getKey();
    10             if(CREATION_TIME_ATTR.equals(key)) {
    11                 loaded.setCreationTime((Long) entry.getValue());
    12             } else if(MAX_INACTIVE_ATTR.equals(key)) {
    13                 loaded.setMaxInactiveIntervalInSeconds((Integer) entry.getValue());
    14             } else if(LAST_ACCESSED_ATTR.equals(key)) {
    15                 loaded.setLastAccessedTime((Long) entry.getValue());
    16             } else if(key.startsWith(SESSION_ATTR_PREFIX)) {
    17                 loaded.setAttribute(key.substring(SESSION_ATTR_PREFIX.length()), entry.getValue());
    18             }
    19         }
    20         if(!allowExpired && loaded.isExpired()) {
    21             return null;
    22         }
    23         RedisSession result = new RedisSession(loaded);
    24         result.originalLastAccessTime = loaded.getLastAccessedTime() + TimeUnit.SECONDS.toMillis(loaded.getMaxInactiveIntervalInSeconds());
    25         result.setLastAccessedTime(System.currentTimeMillis());
    26         return result;
    27     }
    View Code
     1         @Override
     2         public HttpSession getSession(boolean create) {
     3             HttpSessionWrapper currentSession = getCurrentSession();
     4             if(currentSession != null) {
     5                 return currentSession;
     6             }
     7             String requestedSessionId = getRequestedSessionId();
     8             if(requestedSessionId != null) {
     9                 S session = sessionRepository.getSession(requestedSessionId);
    10                 if(session != null) {
    11                     this.requestedSessionIdValid = true;
    12                     currentSession = new HttpSessionWrapper(session, getServletContext());
    13                     currentSession.setNew(false);
    14                     setCurrentSession(currentSession);
    15                     return currentSession;
    16                 }
    17             }
    18             if(!create) {
    19                 return null;
    20             }
    21             S session = sessionRepository.createSession();
    22             currentSession = new HttpSessionWrapper(session, getServletContext());
    23             setCurrentSession(currentSession);
    24             return currentSession;
    25         }
    View Code

  • 相关阅读:
    __init__ 构造行数的用法
    Android SDK下载安装及配置教程
    每条用例执行10次
    Python Json模块中dumps、loads、dump、load函数介绍
    Python接口测试实战2
    linux 下添加环境变量 和刷新
    mysql 练习题笔记
    http请求脚本排错指南
    docker命令及其常用事项
    anaconda 环境
  • 原文地址:https://www.cnblogs.com/abcwt112/p/6890768.html
Copyright © 2020-2023  润新知