Session 还在靠“粘滞”苟活?——Spring Session + Redis 让你从“运气好”升级到“可控”!
🏆本文收录于《滚雪球学SpringBoot 3》:
https://blog.csdn.net/weixin_43970743/category_12795608.html,专门攻坚指数提升,本年度国内最系统+最专业+最详细(永久更新)。
本专栏致力打造最硬核 SpringBoot3 从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。 如果想快速定位学习,可以看这篇【SpringBoot3教程导航帖】https://blog.csdn.net/weixin_43970743/article/details/151115907,你想学习的都被收集在内,快速投入学习!!两不误。
若还想学习更多,可直接前往《滚雪球学SpringBoot(全版本合集)》:https://blog.csdn.net/weixin_43970743/category_11599389.html,涵盖SpringBoot所有版本教学文章。
演示环境说明:
- 开发工具:IDEA 2021.3
- JDK版本: JDK 17(推荐使用 JDK 17 或更高版本,因为 Spring Boot 3.x 系列要求 Java 17,Spring Boot 3.5.4 基于 Spring Framework 6.x 和 Jakarta EE 9,它们都要求至少 JDK 17。)
- Spring Boot版本:3.5.4(于25年7月24日发布)
- Maven版本:3.8.2 (或更高)
- Gradle:(如果使用 Gradle 构建工具的话):推荐使用 Gradle 7.5 或更高版本,确保与 JDK 17 兼容。
- 操作系统:Windows 11
前言:一台机器没事,两台机器就开始“闹脾气”了🙃
Web 应用刚起步时,HttpSession 简直像“温柔乡”:登录态、购物车、验证码,一股脑塞进去,爽得很。
可一旦你上了负载均衡,或者搞了多个实例,剧情马上变得很现实:
- 用户 A 第一次请求落到实例 1,Session 在实例 1 的内存里;
- 下一次请求被打到实例 2 —— Session 没了;
- 然后你开始怀疑人生:“我明明没动代码啊?”😵💫
这就是分布式会话管理要解决的核心问题:Session 在哪里、怎么共享、如何隔离、序列化怎么选、Cookie 怎么控。
Spring Session 的目标也很明确:提供一套 API 与实现,让你在不绑定容器实现的前提下,支持集群化 Session。
1. Session 粘滞 vs Session 共享:到底谁在“治本”?🤔
1.1 Session 粘滞(Sticky Session / Affinity):看起来省事,实际上很“脆”
粘滞会话的思路是:负载均衡器尽量把同一个用户的请求总是转发到同一台实例上。
优点很直观:
- 不需要额外存储,继续用内存 Session
- 改动小,上线快
但它的问题也很扎心:
- 容灾差:实例挂了,用户 Session 跟着陪葬
- 扩缩容抖动:实例增减会打破映射,用户被迫重新登录
- 流量不均:热点用户容易把某台实例压爆
- 跨协议/跨入口复杂:比如 Web + App + 网关多层转发,粘滞策略越来越像“补丁叠补丁”😅
1.2 Session 共享:把状态放到“大家都能拿到”的地方
Session 共享的思路是:把 Session 数据放到外部存储(Redis/JDBC 等),所有实例读写同一份 Session。
这就是 Spring Session 最常见的落地方式:Redis 存 Session。
Spring Session 的 Redis 配置文档也强调:会话数据存储在 Redis 中,并且提供不同实现(如 RedisSessionRepository / RedisIndexedSessionRepository)以适应不同查询需求。
2. 集成 Redis 存储 Session:Spring Boot + Spring Session 的“标准姿势”✅
下面按“能直接抄走跑起来”的节奏写(我知道你要的是这个😄)。
2.1 依赖(Maven 示例)
常见组合是:
spring-session-data-redisspring-boot-starter-data-redis
(具体版本跟你的 Spring Boot BOM 对齐即可)
2.2 配置(application.yml)
spring:
session:
# Servlet 项目用 Spring Session 管理 HttpSession
# 具体 store 类型由依赖与自动配置决定;这里给个明确意图
timeout: 30m
data:
redis:
host: 127.0.0.1
port: 6379
关于超时:Spring Boot 文档明确指出可以用 spring.session.timeout 设置 Session 超时时间;若不设置,会回退到 server.servlet.session.timeout。
2.3 需要显式 @EnableRedisHttpSession 吗?
- Spring Boot 场景:多数情况下依赖齐全会走自动配置,你可以先不写注解。
- 你要更细控制(比如 flushMode/saveMode/namespace 等):可以使用
@EnableRedisHttpSession,它的配置语义(如 ON_SAVE 等)在 API 文档里有说明。
3. 自定义 Session 序列化策略:JSON vs JDK Serialization(别只看“可读性”,也要看“坑位”😅)
3.1 默认是什么?
Spring Session Redis 默认使用 Java Serialization(JDK 序列化) 来序列化 Session 属性。官方文档点得很直白:默认 Java 序列化在多应用共享 Redis、类版本不一致时可能会出问题。
JDK 序列化的典型痛点
- Redis 里是二进制,不可读(排查不友好)
- 需要
Serializable,对象一变更容易兼容性炸裂 - 多服务共享同一 Redis、但类版本不一致时,反序列化风险更高
3.2 JSON 序列化(推荐更稳的“跨服务/跨版本”体验)
Spring Session 文档明确:你可以提供一个 RedisSerializer bean 来自定义会话如何序列化到 Redis;并点名 Spring Data Redis 的 GenericJackson2JsonRedisSerializer 可用。
做法:提供 springSessionDefaultRedisSerializer Bean
(这个名字很关键:Spring Session 会按约定去找默认序列化器)
@Configuration
public class SessionSerializationConfig {
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
// 使用 Jackson 的通用 JSON 序列化,包含类型信息,兼容性更强
return new GenericJackson2JsonRedisSerializer();
}
}
JSON 的注意点(别装没看见🙈)
- JSON 序列化会把类型信息写进去(GenericJackson2JsonRedisSerializer 会处理这点),否则反序列化会丢类型
- Session 里如果塞了“奇怪对象”(比如带懒加载代理的实体、巨大对象图),不管 JSON 还是 JDK 都会疼
- 建议:Session 里只放轻量、稳定、可序列化的 DTO/标识(比如 userId、role、少量权限信息)
4. 同域名下多应用 Session 隔离与共享:CookieSerializer 才是“分隔线”🍪
这里是最容易“看起来都配置了,但就是不对”的地方。因为你以为你在搞 Redis,其实你在搞 Cookie😅
Spring Session 的“自定义 Cookie”指南明确:你可以暴露 CookieSerializer Bean 来配置 Cookie 行为,Spring Session 自带 DefaultCookieSerializer。
而 DefaultCookieSerializer 的 API 里也清楚列出了 cookieName、path、domain、sameSite 等控制项(默认 SameSite=Lax)。
4.1 先说结论:共享与隔离,本质看两件事
✅ 想“共享 Session”(同域名不同应用互通登录态)
你需要让这些应用:
- 写入同一个 Session ID Cookie(cookieName/domain/path 一致)
- 访问同一份 Redis Session 数据(同一 Redis + 同一 namespace)
✅ 想“隔离 Session”(互不影响)
你可以在任意一个维度做隔离:
- Cookie 隔离:不同
cookieName或不同cookiePath - Redis 隔离:不同
spring.session.redis.namespace(推荐)
Spring Session Redis 配置文档明确提到:Spring Session 用 namespace(默认 spring:session)来隔离不同应用的会话数据,并可通过 spring.session.redis.namespace 指定。
4.2 实战:同域名多应用“隔离”(最常见,最安全)
假设你有:
app-a.example.comapp-b.example.com
你希望它们登录态互不影响。
方案 A:Redis namespace 隔离(强烈推荐)
app-a:
spring:
session:
redis:
namespace: app-a:session
app-b:
spring:
session:
redis:
namespace: app-b:session
这样即使 cookieName 一样,Redis key 也隔开了(更稳)。
方案 B:CookieName 隔离(也常用)
@Configuration
public class SessionCookieConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("SESSION_APP_A");
serializer.setCookiePath("/");
return serializer;
}
}
DefaultCookieSerializer 支持设置 Cookie 名称、Path、Domain、SameSite 等。
4.3 实战:同主域名下多应用“共享”(单点登录味道😄)
场景:
a.example.com与b.example.com希望共享 Session(同一登录态)
关键是把 Cookie 的 domain 设置成主域example.com,并确保 cookiePath 通常为/。
@Configuration
public class SharedSessionCookieConfig {
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("SESSION");
serializer.setCookiePath("/");
serializer.setDomainName("example.com"); // 让子域共享
serializer.setSameSite("Lax"); // 默认就是 Lax,可按需改
return serializer;
}
}
DefaultCookieSerializer#setSameSite 的默认值是 Lax(API 文档注明)。
小提醒:如果你在本地用
localhost测子域共享,domain 规则会比较别扭;建议用 hosts 文件映射一个测试域名来验证(不然你会怀疑配置没生效,实际是浏览器 cookie 规则在“守法”😂)。
5. 你会在生产环境踩的几个“高频雷区”💥(提前说清楚,省得你线上背锅)
5.1 Session 里放了“巨大对象/不可序列化对象”
- JDK 序列化会直接炸或存储膨胀
- JSON 序列化可能循环引用、类型丢失、性能抖动
建议:Session 只放稳定的小对象(id/少量字段)。
5.2 多应用共享 Redis 却没隔离 namespace
结果:
- A 应用写的 Session,B 应用误读、或因类版本不同反序列化失败
Spring Session 文档已经点过这个风险,并提供 namespace 作为隔离手段。
5.3 Cookie 域/路径没配对
- 你以为共享,实际上 cookie 发不到另一个应用
- 你以为隔离,实际上 cookieName 一样 + path 一样,浏览器照样带过去
DefaultCookieSerializer这类配置要和你的域名/部署路径强绑定思考。
结尾:你要的不是“能跑”,是“可预期”🙂
说到底,分布式 Session 管理就是把“用户状态”从单机内存搬到一个更可靠的地方,并把 Cookie/序列化/命名空间这些边界划清楚。
粘滞会话能救急,但救不了长期;Spring Session + Redis 才是把系统从“看缘分”拉回“可控”的方案。
🧧福利赠与你🧧
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G PDF编程电子书、简历模板、技术文章Markdown文档等海量资料。
ps:本文涉及所有源代码,均已上传至Gitee:
https://gitee.com/bugjun01/SpringBoot-demo开源,供同学们一对一参考 Gitee传送门https://gitee.com/bugjun01/SpringBoot-demo,同时,原创开源不易,欢迎给个star🌟,想体验下被🌟的感jio,非常感谢❗
🫵 Who am I?
我是 bug菌:
- 热活跃于 CSDN:
https://blog.csdn.net/weixin_43970743| 掘金:https://juejin.cn/user/695333581765240| InfoQ:https://www.infoq.cn/profile/4F581734D60B28/publish| 51CTO:https://blog.51cto.com/u_15700751| 华为云:https://bbs.huaweicloud.com/community/usersnew/id_1582617489455371| 阿里云:https://developer.aliyun.com/profile/uolxikq5k3gke| 腾讯云:https://cloud.tencent.com/developer/user/10216480/articles等技术社区; - CSDN 博客之星 Top30、华为云多年度十佳博主&卓越贡献奖、掘金多年度人气作者 Top40;
- 掘金、InfoQ、51CTO 等平台签约及优质作者;
- 全网粉丝累计 30w+。
更多高质量技术内容及成长资料,可查看这个合集入口 👉 点击查看:https://bbs.csdn.net/topics/612438251 👈️
硬核技术公众号 「猿圈奇妙屋」https://bbs.csdn.net/topics/612438251 期待你的加入,一起进阶、一起打怪升级。
- End -
- 点赞
- 收藏
- 关注作者
评论(0)