
在当今互联网大厂的后端技术开发领域,随着业务规模的不断扩大,分布式系统的应用越来越广泛。而在分布式架构下,实现共享 Session 成为了一个关键的技术挑战。今天,我们就来深入探讨一下在 Spring Boot3 中如何巧妙地实现共享 Session。
为什么需要共享 Session想象一下,你正在访问一个大型电商平台,在浏览商品的过程中,你将心仪的商品加入了购物车。当你切换页面或者刷新时,购物车中的商品信息却消失了,这是多么糟糕的体验。在分布式系统中,如果不实现共享 Session,类似的问题就极有可能发生。因为来自同一用户的 Http 请求可能会被分发到不同的 web 站点中,而传统的 HttpSession 是由 Servlet 容器创建和管理并保存在内存中的,不同站点无法共享内存中的 Session 数据。所以,为了确保用户在不同页面、不同请求之间能够保持一致的会话状态,共享 Session 势在必行。
实现共享 Session 的思路常见解决方案剖析
最简单的想法就是把 session 数据保存到内存以外的一个统一的地方,例如 Memcached/Redis 等数据库中。不过紧接着新问题就来了,如何替换掉 Servlet 容器创建和管理 HttpSession 的实现呢?目前主要有两种思路:
设计 Filter 接管 Session 工作:利用 HttpServletRequestWrapper,设计一个 Filter 来实现自己的 getSession () 方法,spring-session 就是基于这样的思路实现的。利用 Servlet 容器插件功能:利用 Servlet 容器提供的插件功能,自定义 HttpSession 的创建和管理策略,并通过配置的方式替换掉默认的策略。但是这种方式存在缺点,它需要耦合 Tomcat/Jetty 等 Servlet 容器的代码,例如 memcached-session-manager 以及 tomcat-redis-session-manager,暂时都只支持 Tomcat6/Tomcat7。Spring Session 闪亮登场
Spring Session 作为 spring 的项目之一(GitHub 地址:https://github.com/spring-projects/spring-session ),为我们提供了一套完美的创建和管理 Servlet HttpSession 的方案。它不仅提供了集群 Session(Clustered Sessions)功能,还默认采用外置的 Redis 来存储 Session 数据,以此来轻松解决 Session 共享的问题。并且,Spring Session 还具备众多强大的功能:
HttpSession 替换:可以以一种与应用容器(如 Tomcat)无关的方式替换 HttpSession。多浏览器会话管理:支持在单个浏览器实例中管理多个用户的会话(例如类似于 Google 的多个已认证账户)。RESTful APIs 支持:允许在请求头中提供会话 ID,以适配 RESTful APIs。WebSocket 支持:在接收 WebSocket 消息时,能够保持 HttpSession 处于活跃状态。在 Spring Boot3 中实现共享 Session添加依赖
在项目的构建文件中,添加相关依赖。如果使用 Maven,在pom.xml中添加:
<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId></dependency><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency>配置 Redis
在application.properties或者application.yml文件中配置 Redis 连接信息和 Spring Session 设置。
spring: redis: host: localhost port: 6379 session: store-type: redis redis: namespace: spring:session flush-mode: on-save timeout: 1800s启用 Redis 的 Spring Session
Spring Boot 会自动检测到spring-session-data-redis依赖,并将会话存储切换到 Redis,实现会话共享。一般来说,在启动类上添加@EnableRedisHttpSession注解即可启用相关功能,例如:
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)public YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); }}其中maxInactiveIntervalInSeconds参数用于设置 Session 的失效时间。
编写一个简单的 Controller 来测试 Session 共享是否成功。
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.HttpSession;import java.util.Collections;import java.util.Map;@RestController@RequestMapping("/session")public SessionController { @GetMapping("/set") public Map<String, String> setSession(HttpSession session) { session.setAttribute("username", "tech_sharer"); return Collections.singletonMap("result", "success"); } @GetMapping("/get") public Map<String, String> getSession(HttpSession session) { String username = (String) session.getAttribute("username"); return Collections.singletonMap("username", username); }}通过访问/session/set设置 Session 属性,再访问/session/get获取该属性,如果能够正确获取,那就说明 Session 共享已经成功实现啦。
微信小程序与 Spring Boot3 共享 Session在微信小程序与 Spring Boot3 集成共享 Session 时,可能会遇到一些特殊情况。例如,之前在 Spring Boot2.4.5 版本下,将服务器的 session id 发送给小程序保存,每次请求时带上该 session id 即可实现共享。但在 Spring Boot3.2.5 中,此方法可能会失败,小程序每次请求时 session id 依然变化。此时,需要通过小程序的 response Header 信息重新提取 session id 进行保存。
在小程序端代码如下:
var session = res.header('Set-Cookie').split(";")[0].split("=")[1]wx.setStorageSync('WX_SESSION', session);服务器端需要正常配置 Spring Boot 与 Redis 相关依赖及配置,确保 Session 存储到 Redis 中。后续小程序请求时,将保存的 session id 放到请求头的 Cookie 中:
var session_id = wx.getStorageSync('WX_SESSION')var header = { 'content-type': 'application/json', 'Cookie': 'SESSION='+session_id } wx.request({ header: header, url: 地址, method: method方法, data: 参数, success(request) { // 处理成功逻辑 }});非自主维护 Redis 的配置
如果配置的 Redis 不是自己在维护,不能更改其配置(比如应用程序部署在阿里云,同时使用阿里云的 Redis 数据库),在使用 Spring Session 共享 Session 时需要注意。因为默认情况下,可能需要 Redis 开启某些额外功能,而我们无法直接在外部 Redis 上进行配置。此时,可以新建一个 RedisSessionConfig 类,在不改变 Redis 配置的前提下使用 Redis 来存储 Session。
总结在 Spring Boot3 中实现共享 Session,通过 Spring Session 结合 Redis 的方式,能够高效、稳定地解决分布式系统中的会话共享问题。从依赖添加、Redis 配置、功能启用再到测试验证,每一步都有着明确的操作步骤。同时,针对不同的特殊场景,如微信小程序集成、非自主维护 Redis 等情况,也有着相应的解决方案。希望本文能够帮助各位互联网大厂的后端技术开发人员,在项目中顺利实现 Spring Boot3 的共享 Session 功能,为打造更优质的应用程序助力。