Java会话技术之 —— Spring Session

本文介绍了如何使用Spring-Session结合Redis解决分布式环境下的会话共享问题。通过配置Spring-Session和Redis,将session信息存储在Redis中,实现了不同服务器间的会话共享,确保用户在多个服务间切换时仍能保持登录状态。同时,文章提到了自定义session存储key的配置,并留待读者探索如何将会话信息与用户ID关联的实现。
摘要由CSDN通过智能技术生成

前言

在上一篇我们聊到了会话技术的基础原理中session和cookie的使用,基于cookie和session可以实现客户端(浏览器)和服务端的会话存储,从请求的无状态变为一定程度的有状态,在文章最后,通过一个简单的演示,看到这样一种现象,即在分布式环境下,假如客户端第一次携带着JSESSINID访问了A服务器的某个接口,再次访问B服务器相同服务的相同接口时,却发现获取到的JSESSINID值为null

很明显,在分布式环境下,基于单机模式下的session和cookie的值是无法跨进程互通,于是我们想,是否可以通过某种方式将JSESSINID或者说一个客户端与服务端的交互凭证存放在某个存储介质中呢?答案是肯定的

在Java中,提供了多种对于此问题的解决方案,目前使用较多也比较成熟的方案像spring-session,token + redis ,JWT,oauth2等,都可以实现在分布式环境下session共享问题,当然这些方案并不是相互隔离的,可以组合搭配,甚至可以基于某一种做定制化的方案都可以

下面来探讨下小而美的分布式session共享的解决方案的spring-session

spring-session基本原理

spring-session提供了一种扩展存储分布式会话session的解决方案,即通过引入spring-session的相关依赖,可以将会话的session信息存放到指定的存储介质中,可以是mongodb,redis,mysql等,实现自由灵活的存取

下面演示基于redis存储session信息实现分布式会话问题的解决

1、添加基础依赖

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>

    </dependencies>

2、配置yml

server:
  port: 8081

spring:
  #redis基础配置 ###################################
  redis:
    port: 6379
    host: localhost
    database: 1

  #session配置 ###################################
  session:
    store-type: redis
    timeout: 3600s

在这里插入图片描述
可以看到,spring-session提供了丰富的session存储方式,可以根据自己的情况自由选择

3、编写登录接口和获取登录信息接口

@RestController
public class LoginController {

    @GetMapping("/login")
    public String login(HttpSession session,HttpServletRequest request,HttpServletResponse response,
                        String username, String password) {
        if(username.equals("admin") && password.equals("123456")){
            session.setAttribute("login_info",username);
            return "login success:" + username;
        }
        return "login fail:" + username;
    }

    @GetMapping("/info")
    public String getLoginInfo(HttpSession session,HttpServletRequest request,HttpServletResponse response) {
        return "info:" + session.getAttribute("login_info");
    }

}

仍然按照之前的测试方式,通过浏览器观察下session的信息,

调用接口:http://localhost:8081/login?username=admin&password=123456
在这里插入图片描述
这时候发现,cookie一栏不再有JSESSIONID,而是一个SESSION,说明使用了spring-sesion的方式之后,会话信息的存储方式发生了改变

再通过redis的客户端工具观察下redis库中的session存储情况,发现这里多出来了很多和session相关的信息,比如expires表示会话的过期时间等(具体的过期时间可以从TTL的时间看出来)
在这里插入图片描述

这时,再去访问获取会话信息接口:
在这里插入图片描述

既然看到session的信息存储到了redis,即在过期时间范围内持久化了,就算重启,也可以访问,即重启后,再次访问上面的接口仍然可以看到 info:admin

在这里插入图片描述
重启后,再次访问,依然可以访问到会话的信息,下面再启动一个相同的服务,使用端口进行区分

启动成功后,访问:http://localhost:8082/info,发现也可以成功访问到相同的session信息,这样就简单实现了在分布式环境下会话共享的问题
在这里插入图片描述

一个扩展配置

在使用redis存储会话信息时候,默认情况下,保存会话信息的key前缀是以spring开头的,在实际开发过程中,我们希望key带有一定的业务标识,比如redis中存储的会话信息,希望和登录用户的ID有关联,就可以使用下面的这个配置:

session.redis.namespace

在这里插入图片描述
即存储在redis中的session的key就可以按照自定义的方式存储了,删除Session信息重启下项目再次测试,可以看到,可以的前置就是自定义的了
在这里插入图片描述
而实际在开发过程中,更通用的做法是,将保存在redis中的会话信息的key和登录用户的ID进行关联,即在用户登录成功后,保存到redis中,后续在会话有效的时间范围内,用户再次访问时候,通过网关或者通用拦截器校验用户的会话信息即可,着在spring-session中该如何实现呢?这里留下一个小小的疑问,有兴趣的同学可以深入探究下

本篇到此结束,最后感谢观看!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小码农叔叔

谢谢鼓励

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

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

打赏作者

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

抵扣说明:

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

余额充值