Spring Session 是 Spring Framework 的一部分,它提供了一种灵活的方式来管理分布式环境中的 HTTP Session。Spring Session 的核心思想是将 Session 数据从单个应用服务器中抽离出来,存储在一个集中的地方,如 Redis、Memcached 或数据库等,从而解决了分布式环境中 Session 共享的问题。
下面将结合源码简要介绍 Spring Session 的关键组件和工作原理。
初始化配置:
CookieSerializer
和 RedisSerializer
。SessionRepository
实例,如 RedisOperationsSessionRepository
。请求处理:
SessionRepositoryFilter
会拦截该请求。SessionRepositoryFilter
通过 DefaultSessionIdResolver
获取客户端传来的 Session ID。DefaultSessionIdCreator
会创建一个新的 Session ID。SessionRepositoryFilter
通过 SessionRepository
从 Redis 中加载或创建一个新的 Session。DefaultSession
对象,并与请求关联起来。Session 操作:
HttpSession
一样使用 DefaultSession
。Session 保存:
SessionRepositoryFilter
会检测到 Session 是否有变更。SessionRepository
的 save
方法将 Session 保存到 Redis 中。Session 无效:
SessionRepository
会将其从 Redis 中删除。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);
}
}
// ...
}
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);
}
}
// ...
}
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 共享的问题,还保证了应用的可伸缩性和高可用性。
因篇幅问题不能全部显示,请点此查看更多更全内容