问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

深入理解 Spring Session:实现分布式会话管理(含详细步骤)

创作时间:
作者:
@小白创作中心

深入理解 Spring Session:实现分布式会话管理(含详细步骤)

引用
CSDN
1.
https://blog.csdn.net/qq_46248151/article/details/135142857

Spring Session 是 Spring 框架的一个扩展,它提供了一种强大的方式来管理应用程序的会话,尤其适用于分布式系统。在这篇博客中,我们将深入探讨 Spring Session 的工作流程、核心原理、使用场景以及如何在您的应用程序中实现分布式会话管理。

什么是 Spring Session?

Spring Session 是 Spring 框架的一个项目,旨在提供会话管理的解决方案。它可以与各种后端存储(如内存、数据库、Redis 等)集成,以便将会话数据存储在可扩展的分布式环境中。Spring Session 不仅可以用于传统的 Web 应用程序,还可以用于微服务架构中的分布式系统。

Spring Session 的核心概念

在深入研究 Spring Session 之前,让我们了解一些核心概念:

会话(Session):会话是一个用户与应用程序之间的交互周期。在 Web 应用程序中,会话通常涉及用户登录、浏览网页、提交表单等操作。会话数据可以包括用户身份验证状态、购物车内容、用户首选项等。

Spring Session Repository:这是 Spring Session 存储会话数据的地方。它可以与多种后端存储集成,包括内存、数据库、Redis 等。

Session ID(会话标识符):Session ID 是用于标识特定会话的唯一标识符。它通常存储在客户端的 Cookie 中,并用于将客户端请求与服务器端会话关联起来。

Spring Session 的工作流程

Spring Session 的工作原理相对简单,主要涉及以下步骤:

客户端请求:当客户端(通常是浏览器)发送请求到服务器时,会将包含 Session ID 的 Cookie 信息一并发送给服务器。

Session Repository 查询:Spring Session 会根据请求中的 Session ID 查询相应的会话数据。这个查询可以通过内存、数据库(redis)或分布式存储来完成,具体取决于您的配置。

会话创建或恢复:如果找到与 Session ID 相关联的会话数据,Spring Session 会将其加载到内存中,以供后续请求使用。如果没有找到会话数据,将创建一个新的会话。

处理请求:服务器会使用加载或创建的会话数据来处理客户端的请求。这可以包括读取和修改会话属性。

响应发送:服务器将响应发送给客户端,并在响应中包含更新后的 Session ID(如果会话数据有变化)。

客户端 Cookie 更新:客户端接收到服务器响应后,可能会更新 Cookie 中的 Session ID,以便将来的请求能够正确关联到会话。

Spring Session 的核心原理

以redis作为会话存储为例,我们从源代码的层面上去分析SpringSession的核心原理,其关键在于理解@EnableRedisHttpSession做了哪些事情。

1.SessionRepository

@EnableRedisHttpSession除了指定 Spring Session 使用 Redis 作为会话存储之外,还做了一些“隐秘”的操作。既然都用redis存储会话数据了,那很显然我们需要一套类似于MyBatis操作数据库增删改查的repository类来操作相关数据,而在SpringSession里面,SessionRepository就充当了这个角色。具体的,在本例子中是RedisOperationsSessionRepository,

通过查看EnableRedisHttpSession注解的源码,我们发现其导入了一个RedisHttpSessionConfiguration类,在这个类的源码中,向Spring容器提供了RedisOperationsSessionRepository,代码如下:

2.SessionRepositoryFilter

EnableRedisHttpSession注解导入的RedisHttpSessionConfiguration继承了SpringHttpSessionConfiguration,而这个配置类配置了一个SessionRepositoryFilter,通过源码发现其就是一个Filter,他重写了doFilterInternal方法,源码如下:

我们可以发现,对于每一个请求,它将HttpServletRequest和HttpServletResponse都“包装”了一下,包装成了和SessionRepository有关了的“加强”类,在“加强”类中,重写了getSession方法,这里获取到的session就不是原生的session,部分源码如下:

它会有很多基于SessionRepository的操作(可以查看上图完整的源码得知),这样,我们就可以在原来request.getSession().setAttribute(key,value)的用法上,实现基于SpringSession的操作,因为这里的request并不是原始的HttpServletRequest,而是被包装过的SessionRepositoryRequestWrapper,这也就是上文提到的“加强类”,得到的session也是HttpSessionWrapper“加强session”,所以调用的操作就是SpringSession操作redis等等。

3.总结

SpringSession源码的核心就是利用装饰者模式,通过过滤器Filter将Request、Response、Session类包装成“加强”之后的类,这个加强就提供了众多操作外部存储redis的方法。

Spring Session 的使用场景

Spring Session 可以在许多场景下发挥重要作用:

分布式系统:在微服务架构中,多个服务可能需要共享用户的会话数据。Spring Session 可以将会话数据存储在分布式存储中,确保各个服务之间共享相同的会话状态。

云原生应用:对于云原生应用,Spring Session 可以使应用程序更易于扩展和部署。它提供了无状态的会话管理,允许应用程序实例之间共享用户的会话数据。

高可用性和负载均衡:Spring Session 可以与负载均衡和高可用性部署一起使用,以确保在系统故障或应用程序部署期间不会丢失会话数据。

如何在 Spring Boot 中使用 Spring Session

在 Spring Boot 中使用 Spring Session 非常简单,以redis作为存储session数据为例,主要包括以下步骤:

1. 依赖引入

首先,您需要在项目中引入 Spring Session 和 Redis 的相关依赖。通常,您可以在
pom.xml
文件中添加以下依赖:


<dependency>  
    <groupId>org.springframework.session</groupId>  
    <artifactId>spring-session-core</artifactId>  
    <version>2.5.0</version> <!-- 版本号可能会有变化 -->  
</dependency>  
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-data-redis</artifactId>  
</dependency>  

这些依赖包括 Spring Session 核心库和 Spring Boot 的 Redis 支持。

2. 配置 Redis 连接

接下来,您需要配置 Spring Boot 应用程序以连接到 Redis。通常,在
application.properties

application.yml
中添加 Redis 配置,如下所示:


spring:  
  redis:  
    host: localhost  
    port: 6379  

这将告诉 Spring Boot 应用程序连接到本地的 Redis 服务器。

3. Spring Session 配置

接下来配置 Spring Session,以使用 Redis 作为外部会话存储。可以创建一个配置类,如下所示:


import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;  
@Configuration  
@EnableRedisHttpSession  
public class RedisSessionConfig {  
    @Bean  
    public CookieSerializer cookieSerializer(){  
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();  
        cookieSerializer.setDomainName("lcc.com");//这样就可以实现lcc.com以及lcc.com子域(如:a.lcc.com、b.lcc.com)下的服务之间session共享  
        return cookieSerializer;  
    }  
    // 可以添加其他配置  
}  

@EnableRedisHttpSession
注解告诉 Spring Session 使用 Redis 作为会话存储。

在使用
@EnableRedisHttpSession
启用 Spring Session 集成 Redis 作为会话存储时,通常无需再显式配置
spring.session.store-type=redis
。这是因为
@EnableRedisHttpSession
已经隐式指示 Spring Session 使用 Redis 作为会话存储。

4. 会话操作

到这里即可在应用程序中正常操作会话,就像操作本地会话一样。Spring Session 提供了一些接口和工具,如HttpSession,用于处理会话数据。


import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.session.Session;  
import org.springframework.session.SessionRepository;  
import org.springframework.stereotype.Service;  
@Service  
public class SessionService {  
    @Autowired  
    private SessionRepository sessionRepository;  
    public void storeDataInSession(String key, String value) {  
        Session session = sessionRepository.findById(key);  
        session.setAttribute(key, value);  
        sessionRepository.save(session);  
    }  
    public String getDataFromSession(String key) {  
        Session session = sessionRepository.findById(key);  
        return session.getAttribute(key);  
    }  
}  

在这个示例中,
SessionService
使用
SessionRepository
来存储和检索会话数据。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号