分布式之SpringSession

26 篇文章 0 订阅
6 篇文章 0 订阅

1、概述

1.1 Web中的Session和Cookie回顾

Session机制

由于HTTP协议是无状态的协议,一次浏览器和服务器的交互过程就是:
浏览器:你好吗?
服务器:很好!
这就是一次会话,对话完成后,这次会话就结束了,服务器端并不能记住这个人,下次再对话时,服务器端并不知道是上一次的这个人,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是Session。

Cookie
服务端如何识别特定的客户?
这个时候需要使用Cookie。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。
实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session时,服务端会在HTTP协议中向客户端 Cookie 中记录一个Session ID,以后每次请求把这个会话ID发送到服务器,这样服务端就知道客户端是谁了。

url重写
那么如果客户端的浏览器禁用了 Cookie 怎么办?
一般这种情况下,会使用一种叫做URL重写的技术来进行session会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sessionId=xxxxx 这样的参数,服务端据此来识别客户端是谁

1.2 Session会话管理及带来的问题

在Web项目开发中,Session会话管理是一个很重要的部分,用于存储与记录用户的状态或相关的数据。通常情况下session交由容器(tomcat)来负责存储和管理,但是如果项目部署在多台tomcat中,则session管理存在很大的问题

  • 多台tomcat之间无法共享session,比如用户在tomcat A服务器上已经登录了,但当负载均衡跳转到tomcat B时,由于tomcat B服务器并没有用户的登录信息,session就失效了,用户就退出了登录
  • 一旦tomcat容器关闭或重启也会导致session会话失效。因此如果项目部署在多台tomcat中,就需要解决session共享的问题

1.3 Session会话共享方案

  • 第一种是使用容器扩展插件来实现,比如基于Tomcat的tomcat-redis-session-manager插件,基于Jetty的jetty-session-redis插件、memcached-session-manager插件;这个方案的好处是对项目来说是透明的,无需改动代码,但是由于过于依赖容器,一旦容器升级或者更换意味着又得重新配置。其实底层是,复制session到其它服务器,所以会有一定的延迟,也不能部署太多的服务器。
  • 第二种是使用Nginx负载均衡的ip_hash策略实现用户每次访问都绑定到同一台具体的后台tomcat服务器实现session总是存在。这种方案的局限性是ip不能变,如果手机从北京跳到河北,那么ip会发生变化;另外负载均衡的时候,如果某一台服务器发生故障,那么会重新定位,也会跳转到别的机器。
  • 第三种是自己写一套Session会话管理的工具类,在需要使用会话的时候都从自己的工具类中获取,而工具类后端存储可以放到Redis中,这个方案灵活性很好,但开发需要一些额外的时间。
  • 第四种是使用框架的会话管理工具,也就是我们要介绍的Spring session,这个方案**既不依赖tomcat容器,又不需要改动代码,**由Spring session框架为我们提供,可以说是目前非常完美的session共享解决方案

2、SpringSession

  • Spring Session 是Spring家族中的一个子项目,它提供一组API和实现,用于管理用户的session信息
  • 它把servlet容器实现的httpSession替换为spring-session,专注于解决 session管理问题,Session信息存储在Redis中,可简单快速且无缝的集成到我们的应用中;
    官网:https://spring.io/

Spring Session的特性

  • 提供用户session管理的API和实现
  • 提供HttpSession,以中立的方式取代web容器的session,比如tomcat中的session
  • 支持集群的session处理,不必绑定到具体的web容器去解决集群下的session共享问题

2.1 使用方法概述

  1. 创建maven的web项目
  2. 建向session放数据的servlet
    在这里插入图片描述
  3. 建从session取数据的servlet
    在这里插入图片描述
  4. maven依赖管理。pom.xml文件中添加servlet及jsp的配置
    <dependencies>
          <!-- servlet依赖的jar包start -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
            </dependency>
            <!-- servlet依赖的jar包start -->
    
            <!-- jsp依赖jar包start -->
            <dependency>
                <groupId>javax.servlet.jsp</groupId>
                <artifactId>javax.servlet.jsp-api</artifactId>
                <version>2.3.1</version>
            </dependency>
            <!-- jsp依赖jar包end -->
    
            <!--jstl标签依赖的jar包start -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
            <!--jstl标签依赖的jar包end -->
        </dependencies>
    
  5. 配置各自的tomcat服务器,每个servlet使用不同的端口号。
  6. SpringSession集成配置。((1)在pom.xml文件中,添加Spring Session相关的依赖;(2)在web.xml文件中配置springSessionRepositoryFilter过滤器:(3)在web.xml文件中加载Spring配置文件;(4)创建applicationContext-session.xml;(5)配置redis.properties文件;(6)在applicationContext.xml中导入applicationContext-session.xml)
    (1)
    <!-- Spring session redis 依赖start -->
            <dependency>
                <groupId>org.springframework.session</groupId>
                <artifactId>spring-session-data-redis</artifactId>
                <version>1.3.1.RELEASE</version>
            </dependency>
            <!-- Spring session redis 依赖end -->
            <!-- spring web模块依赖 start -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>4.3.16.RELEASE</version>
            </dependency>
            <!-- spring web模块依赖end -->
    
    (2)
    		<filter>
      		    <filter-name>springSessionRepositoryFilter</filter-name>
    		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    		</filter>
    		<filter-mapping>
    		    <filter-name>springSessionRepositoryFilter</filter-name>
    		    <url-pattern>/*</url-pattern>
    		</filter-mapping>  	
    
    (3)
    		<context-param>
    		    <param-name>contextConfigLocation</param-name>
    		    <param-value>classpath:applicationContext.xml</param-value>
    		</context-param>
    		<listener>
    		  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    		</listener>
    
    (4)
    A、 配置一个RedisHttpSessionConfiguration类
    context:annotation-config/:用于激活已经在Spring容器中注册的bean或者注解,因为我们通过容器创建的bean中,底层有可能使用了其它的注解,我们通过context:component-scan就不能指定具体的包了,所以可以使用context:annotation-config/激活
    <!-- spring注解、bean的处理器 -->
    <context:annotation-config/>
    <!-- Spring session 的配置类 -->
    <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
    
    B、 配置Spring-data-redis
    <!-- 配置jedis连接工厂,用于连接redis -->
    <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.hostName}"/>
        <property name="port" value="${redis.port}"/>
        <property name="password" value="${redis.password}"/>
        <property name="usePool" value="${redis.usePool}"/>
        <property name="timeout" value="${redis.timeout}"/>
    </bean>
    <!--读取redis.properties属性配置文件-->
    <context:property-placeholder location="classpath:redis.properties"/>
    
    (5)
    redis.hostName=192.168.235.128
    redis.port=6379
    redis.password=123456
    redis.usePool=true
    redis.timeout=15000
    
    (6)在这里插入图片描述点击config将这两个配置文件进行关联
    在这里插入图片描述
  7. 部署测试。(启动redis;启动两台tomcat;set完get)

3、应用场景

3.1 同域名下相同项目(集群环境)实现Session共享

在这里插入图片描述

3.2 同域名下不同项目实现Session共享

在这里插入图片描述

3.3 单点登录不支持

  • 对于不同根域名的场景,要实现一处登录,处处登录,Spring Session不支持
  • 单点登录(Single Sign On),简称为 SSO,是流行的企业业务整合的解决方案之一,SSO是指在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统

4 Spring Session的执行流程(源码分析)

  1. 页面请求被全局的过滤器org.springframework.web.filter.DelegatingFilterProxy过滤
  2. 全局的过滤器是一个代理过滤器,它不执行真正的过滤逻辑,它代理了一个Spring容器中的名为springSessionRepositoryFilter 的一个过滤器
  3. 代理的这个 springSessionRepositoryFilter 过滤器是从spring容器中获取的,真正执行过滤逻辑的是SessionRepositoryFilter
    @Bean注解
    		相当于: 
    		<bean id="springSessionRepositoryFilter" class="xx.xxx.xx.SessionRepositoryFilter">
    		      ........
    		</bean>
    
  4. 该SessionRepositoryFilter过滤器覆盖了原来servlet中的request和response接口中定义的操作session方法,替换成自己的session方法在过滤的时候,总是会执行一个finally语句块,在finally中提交session,保存到Redis。session以hash结构存放在redis。
  5. 默认的过期时间30分钟
    <!-- Spring session 的配置类 -->
    <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!--设置session过期时间,单位是秒,默认是30分钟-->
        <property name="maxInactiveIntervalInSeconds" value="3600"/>
        <!--设置cookie的存放方式-->
        <property name="cookieSerializer" ref="defaultCookieSerializer"/>
    </bean>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zkFun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值