文章目录

  • 前言
  • 第一节 传统的单点登录示例
  • 第二节 如何解决多服务器session共享的问题
  • 1. 安装redis
  • 2. session共享实践
  • 3. 登出


前言

通常我们的session保存在服务器内存中,那么当我们部署多台服务器时,如何实现session共享?

springboot reactor 登录超时设置 springboot登录session_servlet

第一节 传统的单点登录示例

  1. 新建一个springboot 项目,引入web-starter和lombok
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
  1. 添加模拟登录登出的代码
package com.it2.springbootsession01.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@RestController
@RequestMapping("/sessiontest")
@Slf4j
public class SessionTestController {

    /**
     * 登录
     * @param request
     * @param name
     * @return
     */
    @GetMapping("/login")
    public String login(HttpServletRequest request, String name) {
        log.info("登录:{}", name);
        HttpSession session = request.getSession();
        session.setAttribute("name", name);
        return name + " login success";
    }

    /**
     * 登出
     * @param request
     * @return
     */
    @GetMapping("/logout")
    public String logout(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String name= session.getAttribute("name") + "";
        session.removeAttribute("name");
        log.info("登出:{}", name);
        return name + " logout success";
    }

    /**
     * 获取用户名
     * @param request
     * @return
     */
    @GetMapping("/getusername")
    public String getUsername(HttpServletRequest request) {
        HttpSession session = request.getSession();
        return "hello," + session.getAttribute("name") + "";
    }
}
  1. 启动服务器测试demo是否正常。可以看到登录成功,并且能够获取到用户名。

模拟多服务器,此时在8089再启动一台服务器

springboot reactor 登录超时设置 springboot登录session_spring boot_02


可以发现8089这台服务器并不能获取到用户名,说明session未在多服务器之间共享。server1登录后,server2无法获取到server1的登录信息(session)。

springboot reactor 登录超时设置 springboot登录session_spring boot_03

第二节 如何解决多服务器session共享的问题

我们只需要将session存储到DB里面,两台server共享DB,即可实现sesssion共享。

springboot reactor 登录超时设置 springboot登录session_spring_04


springboot提供了mongodb、redis、jdbc、hazelcast(一款分布式缓存)等方案。

这里我们选择redis作为session共享方案,redis作为noSQL数据库,其性能非常优秀。由于采用了外部的DB存储,所以多节点的部署可以既可以在同一台物理机器上,也可以在不同的物理机器上,没有地理的限制。

那么具体如何实现session共享呢?

1. 安装redis

由于选择了redis的方案,所以需要先拥有一台可用的redis服务器。如果已经有redis,可以忽略。
安装方案:

  • docker安装redis的方案:
docker run -d  --name redis -p 6379:6379 -d redis:latest
  • windows安装redis方案
    一路next即可,没啥难度。
    可参考: https://www.redis.com.cn/redis-installation.html
  • 管理redis的可视化工具
    RedisDesktopManager
    一款桌面的redis管理工具,可以辅助用户查看redis里面的数据,对数据进行操作和管理。
  • springboot reactor 登录超时设置 springboot登录session_spring boot_05

2. session共享实践

下面我们基于前面的代码对项目进行修改,使其实现多服务器之间的session共享。

  1. 导入依赖
<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>
  1. 配置spring-session方案
spring:
      session:
        timeout: 7200 #session失效时间,单位秒
        store-type: redis #spring-session存储配置
      redis:
        port: 6379
        host: localhost
        database: 15 #指定存入redis的哪个库,默认0,可配可不配,这里指定只是为了将登录的内容单独存储
  1. 两个服务都启动,在其中一台服务器进行登录测试,如果两台服务器都能获取到username即视为session实现了共享。

到此,基于redis的多服务器session共享成功。

3. 登出

执行登出操作,可以看到两个服务器都不能获取username,则表明单点登出,多节点都会登出。

springboot reactor 登录超时设置 springboot登录session_servlet_06