Spring Session——会话管理

一、Session会话管理概述

  • 1.Web中的Session和Cookie
    • 1.1.Session机制
      由于HTTP协议是无状态的协议,一次浏览器和服务器的交互过程就是:
      浏览器:你好吗?
      服务器:很好!
      这就是一次会话,对话完成后,这次会话就结束了,服务器端并不能记住这个人,下次再对话时,服务器端并不知道是上一次的这个人,所以服务端需要记录用户的状态时,就需要用某种机制来识别具体的用户,这个机制就是Session。
    • 1.2.Cookie
      服务端如何识别特定的客户?
      这个时候需要使用Cookie。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。
      实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session时,服务端会在HTTP协议中向客户端 Cookie 中记录一个Session ID,以后每次请求把这个会话ID发送到服务器,这样服务端就知道客户端是谁了。
    • 1.3.url重写
      那么如果客户端的浏览器禁用了 Cookie 怎么办?
      一般这种情况下,会使用一种叫做URL重写的技术来进行session会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sessionId=xxxxx 这样的参数,服务端据此来识别客户端是谁
  • 2.Session会话管理及带来的问题
    • 在Web项目开发中,Session会话管理是一个很重要的部分,用于存储与记录用户的状态或相关的数据。
    • 通常情况下session交由容器(tomcat)来负责存储和管理,但是如果项目部署在多台tomcat中,则session管理存在很大的问题
      • 多台tomcat之间无法共享session,比如用户在tomcat A服务器上已经登录了,但当负载均衡跳转到tomcat B时,由于tomcat B服务器并没有用户的登录信息,session就失效了,用户就退出了登录
      • 一旦tomcat容器关闭或重启也会导致session会话失效
      • 因此如果项目部署在多台tomcat中,就需要解决session共享的问题
  • 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共享解决方案

二、Spring Session

  • 1.Spring Session简介

    • 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.使用session(先不使用spring session)

    • 创建一个springboot项目,选中web依赖
      在这里插入图片描述
    • 创建一个两个controller
    @RestController
    public class SetSessionController{
    	
    	@RequestMapping("/setSession")
    	public String setSession(HttpSession session) {
    		session.setAttribute("url", "www.baidu.com");
    		return "OK";
    	}
    }
    
    @RestController
    public class GetSessionController {
       @RequestMapping("/getSession")
       public String setSession(HttpSession session) {
       	String value = (String) session.getAttribute("url");
       	if(StringUtils.isEmpty(value)) {
       		value="no session";
       	}
       	return value;
       }
    }
    
    • 然后启动项目,并分别执行set和get,get可以取到值
      在这里插入图片描述
    • 接下来改为两个微服务
      在这里插入图片描述
    • 我们在8001中执行set,在8002中执行get
      在这里插入图片描述
    • 结果8002中取不到值
  • 3.在项目中加入spring session

    • 加入依赖pom.xml
    <!-- springsession框架依赖 -->
    	<dependency>
    		<groupId>org.springframework.session</groupId>
    		<artifactId>spring-session-core</artifactId>
    	</dependency>
    	<!-- springsession与redis的整合依赖 -->
    	<dependency>
    		<groupId>org.springframework.session</groupId>
    		<artifactId>spring-session-data-redis</artifactId>
    	</dependency>
    	<!-- springboot与redis的整合依赖 -->
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-data-redis</artifactId>
    	</dependency>
    
    • 配置redis:application.yml
    spring:
      redis:
        host: 127.0.0.1
        port: 6379
    
    • 再次执行set和get
      在这里插入图片描述
    • 此时redis中也有了数据
      在这里插入图片描述
  • spring session中的一些配置

    • 上面的两个微服务项目的上下文路径是一样的,我们将其改成不一样
      • http://localhost:8001//a/setSession
      • http://localhost:8002//b/getSession
    • 此时再去分别执行set和get,我们发现又取不到值了
      在这里插入图片描述
    • 此时我们查看cookies
      在这里插入图片描述
      在这里插入图片描述
    • 发现两个项目的路径是不同的,如果想让8002从session中取到8001存放的数据我们需要将路径改为一致
    • 创建一个SpringSessionConfig ,用来配置信息
    @SpringBootConfiguration
    public class SpringSessionConfig {
    	@Autowired
    	private DefaultCookieSerializer cookieSerializer;
    	
    	@Bean
    	public RedisHttpSessionConfiguration redisHttpSessionConfiguration() {
    		RedisHttpSessionConfiguration redisHttpSessionConfiguration=new RedisHttpSessionConfiguration();
    		//项目不同实现session共享需要配置的内容
    		cookieSerializer.setCookiePath("/");
    		redisHttpSessionConfiguration.setCookieSerializer(cookieSerializer);
    		return redisHttpSessionConfiguration;
    	}
    }
    

    在这里插入图片描述

    • 子域名不同的时候需要配置主域名的内容
      • cookieSerializer.setDomainName(“session.com”);
      • 例如:
        • 8001的域名为beijing.session.com
        • 8002的域名为shanghai.session.com
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值