Redis实现用户会话

1.分布式会话

(1)什么是会话

会话Session代表的是客户端与服务器的一次交互过程,这个过程可以是连续也可以是时断时续的。曾经的Servlet时代(jsp),一旦用户与服务端交互,服务器tomcat就会为用户创建一个session,同时前端会有一个jsessionid,每次交互都会携带。如此一来,服务器只要在接到用户请求时候,就可以拿到jsessionid,并根据这个ID在内存中找到对应的会话session,当拿到session会话后,那么我们就可以操作会话了。会话存活期间,我们就能认为用户一直处于正在使用着网站的状态,一旦session超期过时,那么就可以认为用户已经离开网站,停止交互了。用户的身份信息,我们也是通过session来判断的,在session中可以保存不同用户的信息。

示例代码如下:

java 复制代码
@GetMapping("/setSession")
public Object setSession(HttpServletRequest request) {
    HttpSession session = request.getSession();
    session.setAttribute("userInfo", "new user");
    session.setMaxInactiveInterval(3600);
    session.getAttribute("userInfo");
    // session.removeAttribute("userInfo");
    return "ok";
}

(2)无状态会话

HTTP请求是无状态的,用户向服务端发起多个请求,服务端并不会知道这多次请求都是来自同一用户,这个就是无状态的。cookie的出现就是为了有状态的记录用户。

常见的,ios与服务端交互,安卓与服务端交互,前后端分离,小程序与服务端交互,他们都是通过发起http来调用接口数据的,每次交互服务端都不会拿到客户端的状态,但是我们可以通过手段去处理,比如每次用户发起请求的时候携带一个userid或者user-token,如此一来,就能让服务端根据用户id或token来获得相应的数据。每个用户的下一次请求都能被服务端识别来自同一个用户。

(3)有状态会话

Tomcat中的会话,就是有状态的,一旦用户和服务端交互,就有会话,会话保存了用户的信息,这样用户就"有状态"了,服务端会和每个客户端都保持着这样的一层关系,这个由容器来管理(也就是tomcat),这个session会话是保存到内存空间里的,如此一来,当不同的用户访问服务端,那么就能通过会话知道谁是谁了。tomcat会话的出现也是为了让http请求变的有状态。如果用户不再和服务端交互,那么会话超时则消失,结束了他的生命周期。如此一来,每个用户其实都会有一个会话被维护,这就是有状态会话。

场景:在传统项目或者jsp项目中是使用的最多的session都是有状态的,session的存在就是为了弥补http的无状态。

注:tomcat会话可以通过手段实现多系统之间的状态同步,但是会损耗一定的时间,一旦发生同步那么用户请求就会等待,这种做法不可取。

(4)单Tomcat会话(图)

先来看一下单个tomcat会话,这个就是有状态的,用户首次访问服务端,这个时候会话产生,并且会设置jsessionid放入cookie中,后续每次请求都会携带jsessionid以保持用户状态。

(5)动静分离会话(图)

用户请求服务端,由于动静分离,前端发起http请求,不会携带任何状态,当用户第一次请求以后,我们手动设置一个token,作为用户会话,放入redis中,如此作为redis-session,并且这个token设置后放入前端cookie中(app或小程序可以放入本地缓存),如此后续交互过程中,前端只需要传递token给后端,后端就能识别这个用户请求来自谁了。

(6)集群分布式系统会话(图)

集群或分布式系统本质都是多个系统,假设这个里有两个服务器节点,分别是AB系统,他们可以是集群,也可以是分布式系统,一开始用户和A系统交互,那么这个时候的用户状态,我们可以保存到redis中,作为A系统的会话信息,随后用户的请求进入到了B系统,那么B系统中的会话我也同样和redis关联,如此AB系统的session就统一了。当然cookie是会随着用户的访问携带过来的。那么这个其实就是分布式会话,通过redis来保存用户的状态。

(7)类似关系:局部变量与全局变量

Tomcat会话相当于一个类中某个方法的局部变量,只能在当前方法中使用;分布式会话相当于一个类中的公用全局变量,可以被类中诸多方法使用。如下代码:

public class DistributedClusterTest {

public String distributedSession = "global-1001";

public void UserSystem() {
    String userSession = "user-2001";

    System.out.println(distributedSession);
    System.out.println(orderSession);
}

public void OrderSystem() {
    String orderSession = "order-3001";

    System.out.println(distributedSession);
    System.out.println(userSession);
}

}

distributedSession是这个类中的全局变量,可以在其他的方法中被使用到,而userSession和orderSession是在方法中的局部变量,局部变量只能在本方法中使用,全局变量可以在其他方法里都能使用。那么分布式会话和单个tomcat会话其实也是一样的道理。

2.实现redis用户会话

示例代码:将user-token存放在usersVO 中;

java 复制代码
public UsersVO convertUsersVO(Users user){
        String uniqueToken = UUID.randomUUID().toString().trim();
        redisOperator.set(REDIS_USER_TOKEN+":"+user.getId(),uniqueToken);

        UsersVO usersVO =new UsersVO();
        BeanUtils.copyProperties(user,usersVO);
        usersVO.setUserUniqueToken(uniqueToken);
        return usersVO;

    }
java 复制代码
//实现用户的redis会话
UsersVO usersVO = convertUsersVO(userResult);
//设置cookie的值,使用工具类cookieutils
CookieUtils.setCookie(request,response,"user", JsonUtils.objectToJson(usersVO),true);
java 复制代码
// 用户退出登录,清楚cookie信息     
redisOperator.del(REDIS_USER_TOKEN+":"+userId);
//分布式会话中需要清除用户数据
CookieUtils.deleteCookie(request, response, xxx);

3.SpringSession实现用户会话

SpringSession介绍

Springsession框架就是解决方案,提供一组API和实现,用于管理用户的session信息,

它把servlet容器实现的httpsession替换成Springsession,专注于解决session管理问题,

Session信息存储在Redis中,可简单快速无缝的集成到我们的应用中。

SpringSession的特性:提供用户session管理的API和实现;提供HttpSession,以

中立的方式取代web容器的session,比如tomcat中的session;支持集群的session处理,

不必绑定具体的web容器去解决集群下的session共享问题

引入SpringSession(分别是springsession的引入以及Spring安全框架):

java 复制代码
<dependency>
	<groupId>org.springframework.session</groupId>
	<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>
</dependency>

配置存储类型

java 复制代码
spring:
  session:
    store-type: redis

开启redis作为SpringSession

@EnableRedisHttpSession // 开启使用redis作为spring session
去除安全自动装配

@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})

代码实现:

java 复制代码
 @GetMapping("/setSession")
    public Object setSession(HttpServletRequest request){

        HttpSession session = request.getSession();
        session.setAttribute("userInfo","new user");
        session.setMaxInactiveInterval(3600);
        session.getAttribute("userInfo");
//        session.removeAttribute("userInfo");

        return "ok";
    }

**总结:**SpringSession:通过httpServletRequest去获取session。HttpSession:就是一个Springsession,包含了一些相应的会话机制,由Spring来进行管理。缺点:耦合度比较高

建议使用Redis,调用redis中相关的值存取就会更加方便。

对于SpringSession的补充:HTTP协议本身是无状态的,为了保存会话信息,

浏览器Cookie通过SessionId标识会话请求,服务器以sessionID为key来存储会话信息。

通常情况下,session交由tomcat容器来负责存储和管理。但是如果项目部署在多台tomcat,

对于session的管理就会存在很大问题。多台tomcat之间无法共享session。

相关推荐
运维小文2 分钟前
服务器硬件介绍
运维·服务器·计算机网络·缓存·硬件架构
李少兄12 分钟前
解决Spring Boot整合Redis时的连接问题
spring boot·redis·后端
日里安28 分钟前
8. 基于 Redis 实现限流
数据库·redis·缓存
EasyCVR1 小时前
ISUP协议视频平台EasyCVR视频设备轨迹回放平台智慧农业视频远程监控管理方案
服务器·网络·数据库·音视频
Elastic 中国社区官方博客1 小时前
使用真实 Elasticsearch 进行更快的集成测试
大数据·运维·服务器·数据库·elasticsearch·搜索引擎·集成测试
明月与玄武2 小时前
关于性能测试:数据库的 SQL 性能优化实战
数据库·sql·性能优化
PGCCC3 小时前
【PGCCC】Postgresql 存储设计
数据库·postgresql
PcVue China5 小时前
PcVue + SQL Grid : 释放数据的无限潜力
大数据·服务器·数据库·sql·科技·安全·oracle
魔道不误砍柴功7 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
jerry6097 小时前
7天用Go从零实现分布式缓存GeeCache(改进)(未完待续)
分布式·缓存·golang