文章目录
Spring Session 原理概述
Spring Session 是 Spring Framework 的一部分,它提供了一种灵活的方式来管理分布式环境中的 HTTP Session。Spring Session 的核心思想是将 Session 数据从单个应用服务器中抽离出来,存储在一个集中的地方,如 Redis、Memcached 或数据库等,从而解决了分布式环境中 Session 共享的问题。
下面将结合源码简要介绍 Spring Session 的关键组件和工作原理。
关键组件
- HttpSessionStrategy:这是一个接口,定义了如何处理 HTTP Session 的创建、更新和销毁等操作。
- AbstractHttpSessionStrategy:这是一个抽象类,实现了
HttpSessionStrategy
接口的基本功能,为具体的 Session 策略提供了基础实现。 - RedisOperationsSessionRepository:这是一个具体的 Session 存储实现,使用 Redis 作为后端存储。
- DefaultCookieSerializer:用于序列化和反序列化 HTTP Cookie。
- DefaultCookieGenerator:生成 Cookie 的策略。
- DefaultSessionIdResolver:用于解析客户端传来的 Session ID。
- DefaultSessionIdCreator:用于创建新的 Session ID。
- SessionRepositoryFilter:这是一个过滤器,用于拦截请求并处理 Session 的逻辑。
工作流程
-
初始化配置:
- 用户配置 Spring Session 的相关 Bean,如
CookieSerializer
和RedisSerializer
。 - Spring Session 会根据配置创建
SessionRepository
实例,如RedisOperationsSessionRepository
。
- 用户配置 Spring Session 的相关 Bean,如
-
请求处理:
- 当客户端发送请求时,
SessionRepositoryFilter
会拦截该请求。 SessionRepositoryFilter
通过DefaultSessionIdResolver
获取客户端传来的 Session ID。- 如果客户端没有提供 Session ID(首次访问或 Session 过期),则
DefaultSessionIdCreator
会创建一个新的 Session ID。 SessionRepositoryFilter
通过SessionRepository
从 Redis 中加载或创建一个新的 Session。- Session 被封装为
DefaultSession
对象,并与请求关联起来。
- 当客户端发送请求时,
-
Session 操作:
- 控制器可以像使用标准的
HttpSession
一样使用DefaultSession
。 - 对 Session 的任何修改都会被记录下来,以便稍后保存到 Redis 中。
- 控制器可以像使用标准的
-
Session 保存:
- 当请求结束时,
SessionRepositoryFilter
会检测到 Session 是否有变更。 - 如果 Session 有变更,则会调用
SessionRepository
的save
方法将 Session 保存到 Redis 中。 - 如果 Session 没有变更,则不会执行保存操作。
- 当请求结束时,
-
Session 无效:
- 如果 Session 过期或被标记为无效,
SessionRepository
会将其从 Redis 中删除。
- 如果 Session 过期或被标记为无效,
源码分析
1. SessionRepositoryFilter
SessionRepositoryFilter
是 Spring Session 中的关键过滤器,它负责处理 Session 的创建、加载、保存和删除等操作。
public class SessionRepositoryFilter extends OncePerRequestFilter {
// ...
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
HttpSession session = null;
boolean sessionCreated = false;
try {
// 1. 从请求中获取 Session ID
String sessionId = this.sessionIdResolver.resolveSessionId(request);
if (sessionId == null) {
// 2. 如果没有 Session ID,则创建一个新的 Session ID
sessionId = this.sessionIdCreator.createSessionId(request, response);
}
// 3. 从 SessionRepository 加载或创建 Session
session = this.sessionRepository.getSession(sessionId, true);
// 4. 将 Session 与请求绑定
bindSessionToRequest(request, session);
// 5. 继续执行过滤器链
filterChain.doFilter(request, response);
// 6. 检查 Session 是否发生了变更
if (session.isNew()) {
sessionCreated = true;
} else if (this.sessionRepository.isChanged(session)) {
sessionCreated = true;
}
// 7. 如果 Session 发生了变更,则保存 Session
if (sessionCreated) {
saveSession(session, response);
}
} finally {
// 8. 清理 Session 与请求的绑定
unbindSessionFromRequest(request, session);
}
}
// ...
}
2. RedisOperationsSessionRepository
RedisOperationsSessionRepository
是一个具体的 SessionRepository
实现,用于与 Redis 进行交互。
public class RedisOperationsSessionRepository implements SessionRepository<DefaultSession> {
// ...
@Override
public DefaultSession createSession() {
// 创建一个新的 Session
DefaultSession session = new DefaultSession(this, this.defaultMaxInactiveIntervalInSeconds);
session.setAttribute(CREATED_TIME_ATTRIBUTE_NAME, System.currentTimeMillis());
return session;
}
@Override
public DefaultSession getSession(String id, boolean create) {
// 从 Redis 中加载 Session
DefaultSession session = loadSession(id);
if (session == null && create) {
// 如果不存在且允许创建,则创建新的 Session
session = createSession();
}
return session;
}
@Override
public void save(DefaultSession session) {
// 保存 Session 到 Redis
if (session.isNew()) {
this.redisTemplate.opsForValue().set(this.keyPrefix + session.getId(), session, session.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS);
} else {
this.redisTemplate.opsForValue().set(this.keyPrefix + session.getId(), session, session.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS);
}
}
// ...
}
3. DefaultSession
DefaultSession
是 Spring Session 中的一个具体 Session 实现,它继承自 AbstractHttpSession
并实现了 HttpSession
接口。
public class DefaultSession extends AbstractHttpSession {
// ...
@Override
public void setAttribute(String name, Object value) {
super.setAttribute(name, value);
// 标记 Session 为已变更
this.changed = true;
}
@Override
public void removeAttribute(String name) {
super.removeAttribute(name);
// 标记 Session 为已变更
this.changed = true;
}
// ...
}
总结
Spring Session 通过一系列组件和策略来管理分布式环境中的 Session。它利用过滤器拦截请求,通过 Session 存储策略(如 Redis)来处理 Session 的创建、加载和保存。这样,不仅解决了分布式环境下 Session 共享的问题,还保证了应用的可伸缩性和高可用性。