Springboot和Spring Session实现session共享

HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保存在内存中的。而如果我们把web服务器搭建成分布式的集群,然后利用LVS或Nginx做负载均衡,那么来自同一用户的Http请求将有可能被分发到两个不同的web站点中去。那么问题就来了,如何保证不同的web站点能够共享同一份session数据呢?

最简单的想法就是把session数据保存到内存以外的一个统一的地方,例如Memcached/Redis等数据库中。

那么问题又来了,如何替换掉Servlet容器创建和管理HttpSession的实现呢?

设计一个Filter,利用HttpServletRequestWrapper,实现自己的 getSession()方法,接管创建和管理Session数据的工作。spring-session就是通过这样的思路实现的。

使用Spring Session和Redis的组合来代替原有的HttpSession实现Session在不同项目之间的共享

在springboot中集成Spring Session

引入spring session相关依赖

<!-- spring session -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

在启动类中配置SpringSession

@SpringBootApplication
//spring在多长时间后强制使redis中的session失效,默认是1800.(单位/秒)
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

配置类中最关键的就是 @EnableRedisHttpSession
@EnableRedisHttpSession 注解创建了一个名为 springSessionRepositoryFilterbean,负责替换 httpSession,同时由 redis 提供缓存支持
为了做到全部替换,我们要确保Servlet容器(Tomcat)对于某个请求都使用这个Filter,这个由SpringBoot负责
(具体是这样的:@EnableRedisHttpSession注解通过Import,引入了RedisHttpSessionConfiguration配置类。该配置类通过@Bean注解,向Spring容器中注册了一个SessionRepositoryFilter(SessionRepositoryFilter的依赖关系:SessionRepositoryFilter --> SessionRepository --> RedisTemplate --> RedisConnectionFactory,有兴趣可以查看源码)
maxInactiveIntervalInSeconds:设置Session失效时间,使用Redis Session之后,原springbootserver.session.timeout属性不再生效

添加验证的接口
yml或者properties文件中可以通过server.port设置端口

@Value("${server.port}")
    String port;

    @GetMapping("/session")
    public Object getSession(HttpServletRequest request){
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("SessionId", request.getSession().getId());
        map.put("ServerPort", "服务端口号为 "+port);
        return map;
    }

可能遇到的问题

错误:java.lang.NoSuchMethodError: org.springframework.data.redis.connection.RedisConnection.getConfig(Ljava/lang/String;)Ljava/util/List;
原因:出现这样的错误应该是引用了spring-session-data-redis1.x版本问题,改用为2.x版本即可

解决方法,引用2.1.2.RELEASE版本
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
    <version>2.1.2.RELEASE</version>
</dependency>

启动测试

访问 http://localhost:8080/session

Paste_Image.png

我们看下redis缓存的数据
Paste_Image.png

可以发现sessionId已经缓存在redis数据库中
下面我们换个端口再访问一次看看
这次我把端口换成了8888 访问:http://localhost:8888/session
Paste_Image.png

刷新了redis数据库,缓存的数据也没变
Paste_Image.png

结果中的SessionId是一致的,却是由两个不同项目工程来提供服务。这样子,SpringSession 利用拦截器 Filter 帮我们在每个请求前进行了同步设置,达到了分布式系统中 session 共享。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 47,338评论 6 342
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 137,073评论 19 139
  • 晚上,闲来无事,照着《唐诗三百首》里一幅插图画临摹了一遍,自我感觉还是不错的。当然,仔细看,笔法还是非常稚嫩的。毕...
    凡心志言阅读 690评论 1 1
  • 我想你了 走在路上想打哈欠 刚张开嘴就吹来寒风 被风噎住的感觉 想你的时候就是这样 无法呼吸
    壹壹不二阅读 151评论 0 1
  • 所谓的坚持,是在状态好的时候继续。在状态不好的时候也继续。这就和跑步一样。人不会总在对的状态。如果突然变得拧巴,难...
    玩儿_温暖阅读 187评论 0 0

友情链接更多精彩内容