• SpringBoot系列: Redis 共享Session


    Web项目Session管理是一个很重要的话题, 涉及到系统横向扩展, SpringBoot已经为共享Session很好的解决方案, 这篇文章关注使用Redis共享会话, 同时这也是最常用的方法. 

    ============================
    pom.xml 增加依赖
    ============================
    SpringBoot2 已经将Redis底层客户端从Jedis切换为Lettuce库, Lettuce 是基于Netty的实现, 比 Jedis 更加高效, 并且是线程安全的, 能满足多线程环境下并发需求, 同时支持线程池.

    使用 Lettuce 客户端(推荐), pom.xml的依赖有:

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-pool2</artifactId>
            </dependency>
            
            <!-- Session 依赖 -->
            <dependency>
                <groupId>org.springframework.session</groupId>
                <artifactId>spring-session-data-redis</artifactId>
            </dependency>        
            
            <!-- 添加缓存支持, 暂时没用上 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-cache</artifactId>
            </dependency>    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>        
            

    如果要使用 Jedis 客户端, pom.xml还需要加上 jedis 依赖包.

            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
            </dependency>   

    ============================
    application.properties 配置
    ============================

    ## Spring cache 设置
    # 使用redis作为cache(暂时没用上)
    spring.cache.type=redis
    
    ## Spring Session 设置
    # 确保 application.properties 文件设定session存储为redis , SpringBoot2支持多种形式的存储, 包括 redis,mongo,jdbc,hazelcase,none等. 
    spring.session.store-type=redis 
    # 指定 session的过期时间,也可在@EnableRedisHttpSession注释参数中指定 
    server.servlet.session.timeout= 
    # Sessions flush mode, 默认是on-save,还可以是 immediate 模式,
    spring.session.redis.flush-mode=on-save 
    # 指定 redis中 session 对应的命名空间
    spring.session.redis.namespace=spring:session
    
    ## redis 公共设置
    spring.redis.host=localhost
    # Redis服务器连接端口
    spring.redis.port=6379
    # Redis服务器连接密码(默认为空)
    spring.redis.password=
    # 连接超时时间(毫秒)
    spring.redis.timeout=10000
    # Redis默认情况下有16个分片,这里配置具体使用的分片
    spring.redis.database=0
     
    ## lettuce 特有的配置:
    # 连接池最大连接数(使用负值表示没有限制) 默认 8
    spring.redis.lettuce.pool.max-active=8
    # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
    spring.redis.lettuce.pool.max-wait=-1
    # 连接池中的最大空闲连接 默认 8
    spring.redis.lettuce.pool.max-idle=8
    # 连接池中的最小空闲连接 默认 0
    spring.redis.lettuce.pool.min-idle=0
    
    ## jedis 特有的配置, 只需要将上面配置文件的 lettuce 文字替换为 jedis 即可. 
    # 连接池最大连接数(使用负值表示没有限制) 默认 8
    spring.redis.jedis.pool.max-active=8
    # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
    spring.redis.jedis.pool.max-wait=-1
    # 连接池中的最大空闲连接 默认 8
    spring.redis.jedis.pool.max-idle=8
    # 连接池中的最小空闲连接 默认 0
    spring.redis.jedis.pool.min-idle=0

    spring.session.redis.flush-mode=on-save 或 immediate
    on-save模式不是在每次通过Session类获取或保存会话信息就调用Redis操作. 对于获取会话信息, 它先尝试从内存HashMap中读取值, 如果没有, 才调用Redis的HMGET操作; 对于保存会话信息, 先保存到内存中, 然后执行web请求的其他工作, 最后才调用Redis的HMSET操作.

    ============================
    增加一个 SessionConfig.java
    ============================

    SessionConfig.java 文件
    @Configuration
    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
    public class SessionConfig {
    }
    
    //@Configuration
    //@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
    //public class SessionConfig {
    //    @Bean
    //    public RedisTemplate<Object, Object> sessionRedisTemplate(RedisConnectionFactory connectionFactory) {
    //        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
    //        template.setKeySerializer(new StringRedisSerializer());
    //        template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
    //        template.setConnectionFactory(connectionFactory);
    //        return template;
    //    }
    //}

    SesionConfig.java 是一个空的类, 该类其实并不是必需的, 必需的其实是@EnableRedisHttpSession注解, 我们可以将 @EnableRedisHttpSession 注解直接加到主程序类, 这样就可以省掉SesionConfig.java .
    加上@EnableRedisHttpSession 注解后, SpringBoot程序在Servlet container 初始化时, 会创建一个 springSessionRepositoryFilter bean, 其实就是一个Filter, 该Fiber负责用 Spring Session替换默认的HttpSession实现.


    ============================
    增加一个 HelloworldController.java文件
    ============================

    @Controller
    @RequestMapping("/test")
    public class HelloworldController {
        @RequestMapping("/set")
        @ResponseBody
        public String set(HttpServletRequest req)    {
            HttpSession session=req.getSession();
            session.setAttribute("testKey", "testValue");
            return "已经设置session:testKey=testValue, SessionId:"+session.getId();
        }
    
        @RequestMapping("/query")
        @ResponseBody
        public Object query(HttpServletRequest req) {
            HttpSession session=req.getSession();
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("SessionId", session.getId());
            map.put("testKey", session.getAttribute("testKey"));
            return map;
        }
    }

    ============================
    测试
    ============================
    测试方法很简单, 使用同一个浏览器先后访问两个应用服务器, 如果能获得同一个session id, 就说明能共享 session 了.

    首先登陆Redis中, 清空所有的key. 

     maven 打包一下这个项目, 执行下面的命令启动两个服务程序. 

    C:Windowssystem32>java -Dserver.port=8080 -jar D:eclipse_workspace edis arget edisSessionDemo.jar
    C:Windowssystem32>java -Dserver.port=9000 -jar D:eclipse_workspace edis arget edisSessionDemo.jar

    在同一个浏览器两个tab页中, 依次访问上面两个服务器:
    http://localhost:8080/test/set
    http://localhost:9000/test/query
    第一个访问8080服务器, 设置session的属性testKey, 第2个访问9000端口, 可以看到页面上输出的session id 是一致的,并能获取到该session的testKey属性.

     

    登录 redis, 输入 keys *session* 命令, 可以查看到这个session id 已经缓存在redis中了. 

    使用 redis type命令得知该session key是 hash table类型, 

    使用 redis hgetall 命令可以查看该hash table的所有字段和取值. 

    ============================
    参考
    ============================
    http://www.cnblogs.com/chenpi/p/6347299.html
    https://www.jianshu.com/p/ece9ac8e2f81
    https://segmentfault.com/a/1190000012490895#idea-redis-
    http://www.cnblogs.com/csonezp/p/6102924.html
    https://blog.csdn.net/dream_broken/article/details/72676679
    https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-redis.html

  • 相关阅读:
    mysql联合主键,也就是两个数据字段一起做主键的情况
    PHP细节,empty,is_null,isset,if()
    PHP细节,PHP手册中常见的一句话:该函数是二进制安全的
    git和github的学习
    用WPS查看两篇word文档异同之处
    js全角字符转为半角字符
    坑(十七)—— Linux无法挂载NTFS格式的U盘
    subprocess模块
    吴裕雄--天生自然--Go 语言学习笔记--Go 语言数组
    吴裕雄--天生自然--Go 语言学习笔记--Go 语言变量作用域
  • 原文地址:https://www.cnblogs.com/harrychinese/p/springboot_redis_session.html
Copyright © 2020-2023  润新知