• 尚好房 11_Session共享


    尚好房:Session共享

    一、业务介绍

    当前我们的服务都是单独部署,web-admin与web-front都使用了session保存当前用户信息,不存在session问题,在生产环境我们的服务都会集群部署多份,如图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BvEcDfet-1661872346930)(images/11/img_001.png)]

    这时就会出现session问题,如果解决呢?session共享

    1. Session共享方案

    Session是服务器用来保存用户操作的一系列会话信息,由Web容器进行管理。单机情况下,不存在Session共享的情况,分布式情况下,如果不进行Session共享会出现请求落到不同机器要重复登录的情况,一般来说解决Session共享有以下几种方案

    1.1 session复制

    session复制是早期的企业级的使用比较多的一种服务器集群session管理机制。应用服务器开启web容器的session复制功能,在集群中的几台服务器之间同步session对象,使得每台服务器上都保存所有的session信息,这样任何一台宕机都不会导致session的数据丢失,服务器使用session时,直接从本地获取。

    这种方式在应用集群达到数千台的时候,就会出现性能瓶颈,每台都需要备份session。

    1.2 session绑定

    利用hash算法,比如nginx的ip_hash,使得同一个Ip的请求分发到同一台服务器上。

    这种方式不符合对系统的高可用要求,因为一旦某台服务器宕机,那么该机器上的session也就不复存在了,用户请求切换到其他机器后没有session,无法完成业务处理。

    1.3 利用cookie记录session

    session记录在客户端,每次请求服务器的时候,将session放在请求中发送给服务器,服务器处理完请求后再将修改后的session响应给客户端。这里的客户端就是cookie。

    利用cookie记录session的也有缺点,比如受cookie大小的限制,能记录的信息有限;每次请求响应都需要传递cookie,影响性能,如果用户关闭cookie,访问就不正常。

    cookie的简单易用,可用性高,支持应用服务器的线性伸缩,而大部分要记录的session信息比较小,因此事实上,许多网站或多或少的在使用cookie记录session。

    1.4 session服务器

    session服务器可以解决上面的所有的问题,利用独立部署的session服务器(集群)统一管理session,服务器每次读写session时,都访问session服务器。

    2. Spring Session

    2.1 Session共享原理

    用户第一次访问应用时,应用会创建一个新的 Session,并且会将 Session 的 ID 作为 Cookie 缓存在浏览器,下一次访问时请求的头部中带着该 Cookie,应用通过获取的 Session ID 进行查找,如果该 Session 存在且有效,则继续该请求,如果 Cookie 无效或者 Session 无效,则会重新生成一个新的 Session
    在普通的 JavaEE 应用中,Session 信息放在内存中,当容器(如 Tomcat)关闭后,内存中的 Session 被销毁;重启后如果当前用户再去访问对应的是一个新的 Session ,在多实例中无法共享,一个用户只能访问指定的实例才能使用相同的 Session;
    Session 共享实现的原理是将原来内存中的 Session 放在一个需要共享 Session 的服务器都可以访问到的位置,如数据库,Redis 等等,从而实现多实例 Session 共享
    实现共享后,只要浏览器的 Cookie 中的 Session ID 没有改变,多个实例中的任意一个被销毁不会影响用户访问。

    2.2 Spring Session共享原理

    当请求进来的时候,SessionRepositoryFilter 会先拦截到请求,将 request 和 response 对象转换成 SessionRepositoryRequestWrapper 和 SessionRepositoryResponseWrapper 。后续当第一次调用 request 的getSession方法时,会调用到 SessionRepositoryRequestWrapper 的getSession方法。这个方法是被重写过的,逻辑是先从 request 的属性中查找,如果找不到;再查找一个key值是"JSESSION"的 Cookie,通过这个 Cookie 拿到 SessionId 去 Redis 中查找,如果查不到,就直接创建一个RedisSession 对象,同步到 Redis 中。

    说的简单点就是:拦截请求,将之前在服务器内存中进行 Session 创建的动作,改成在 Redis 中创建。

    二、Spring Session集成

    我们以web-admin为例,web-front实现方式一样。

    1. shf-parent工程添加依赖管理

    pom.xml

    <redis-session.version>1.3.5.RELEASEredis-session.version>
    
    • 1
    
    <dependency>
        <groupId>org.springframework.sessiongroupId>
        <artifactId>spring-session-data-redisartifactId>
        <version>${redis-session.version}version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2. web-admin工程引入依赖

    
    <dependency>
        <groupId>org.springframework.sessiongroupId>
        <artifactId>spring-session-data-redisartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3. 添加配置

    web-admin项目中创建resources/spring/spring-redis.xml配置文件

    
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
            
            <property name="maxTotal" value="100">property>
            
            <property name="maxIdle" value="50">property>
            
            <property name="testOnBorrow" value="true"/>
            
            <property name="testOnReturn" value="true"/>
        bean>
        
        <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
            <property name="hostName" value="192.168.2.108"/>
            <property name="port" value="6379"/>
            <property name="database" value="0"/>
            <property name="poolConfig" ref="jedisPoolConfig"/>
        bean>
        
        <bean id="redisHttpSessionConfiguration"
              class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
            <property name="maxInactiveIntervalInSeconds" value="600" />
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    4. 添加session共享过滤器

    web.xml

    该过滤器必须是第一个过滤器,所有的请求经过该过滤器后执行后续操作

    
    
    <filter>
      <filter-name>springSessionRepositoryFilterfilter-name>
      <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
    filter>
    <filter-mapping>
      <filter-name>springSessionRepositoryFilterfilter-name>
      <url-pattern>/*url-pattern>
    filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    web.xml完整配置:

    
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://java.sun.com/xml/ns/javaee"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             version="2.5">
        
        <servlet>
            <servlet-name>dispatcherServletservlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
            <init-param>
                <param-name>contextConfigLocationparam-name>
                <param-value>classpath:spring/spring-*.xmlparam-value>
            init-param>
            <load-on-startup>1load-on-startup>
        servlet>
        <servlet-mapping>
            <servlet-name>dispatcherServletservlet-name>
            <url-pattern>/url-pattern>
        servlet-mapping>
    
        
        
        <filter>
            <filter-name>springSessionRepositoryFilterfilter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
        filter>
        <filter-mapping>
            <filter-name>springSessionRepositoryFilterfilter-name>
            <url-pattern>/*url-pattern>
        filter-mapping>
    
        
        
        <filter>
            <filter-name>CharacterEncodingFilterfilter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
            
            <init-param>
                <param-name>encodingparam-name>
                <param-value>UTF-8param-value>
            init-param>
            
            <init-param>
                <param-name>forceRequestEncodingparam-name>
                <param-value>trueparam-value>
            init-param>
            
            <init-param>
                <param-name>forceResponseEncodingparam-name>
                <param-value>trueparam-value>
            init-param>
        filter>
        <filter-mapping>
            <filter-name>CharacterEncodingFilterfilter-name>
            <url-pattern>/*url-pattern>
        filter-mapping>
    
        
        
        <filter>
            <filter-name>springSecurityFilterChainfilter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
        filter>
        <filter-mapping>
            <filter-name>springSecurityFilterChainfilter-name>
            <url-pattern>/*url-pattern>
        filter-mapping>
    web-app>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    5、测试

    重启项目

    访问:http://localhost:8000/,登录。

    通过redis客户端查看redis数据,如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fnoJ4qSh-1661872346935)(images/11/img_002.png)]

    说明:session成功同步到redis数据库中。

    再次测试:

    ​ 1、再次重启web-admin

    ​ 2、再次访问:访问:http://localhost:8000/,页面不会跳转到登录页面,测试成功

    说明:如果session没有同步到redis,那么再次重启,session信息已经清空,就会再次跳转登录,当前没有跳转登录,说明我们的session信息保存到redis。

  • 相关阅读:
    【谢希尔 计算机网络】第3章 数据链路层
    【2023华为杯A题】WLAN网络信道接入机制建模(代码、思路.....)
    文本情感计算技术(深度)
    Spring Cloud学习(十)【Elasticsearch搜索功能 分布式搜索引擎02】
    基于单片机体温脉搏检测控制系统及源程序
    【CSS基础语法】CSS基础语法知识学习笔记汇总
    视频可回溯系统技术方案vue3+ts+tegg+mysql+redis+oss
    Transactional的7种Propagation 事务配置 开启 关闭 spring springboot mybatis
    Angular-Web前端框架
    算法竞赛进阶指南 基本算法 0x02 递推与递归
  • 原文地址:https://blog.csdn.net/lbw18/article/details/126614790