搜索
您的当前位置:首页正文

谷粒商城实战笔记-229-商城业务-认证服务-SpringSession原理

来源:步旅网

Spring Session 原理概述

Spring Session 是 Spring Framework 的一部分,它提供了一种灵活的方式来管理分布式环境中的 HTTP Session。Spring Session 的核心思想是将 Session 数据从单个应用服务器中抽离出来,存储在一个集中的地方,如 Redis、Memcached 或数据库等,从而解决了分布式环境中 Session 共享的问题。

下面将结合源码简要介绍 Spring Session 的关键组件和工作原理。

关键组件

工作流程

  1. 初始化配置

    • 用户配置 Spring Session 的相关 Bean,如 CookieSerializerRedisSerializer
    • Spring Session 会根据配置创建 SessionRepository 实例,如 RedisOperationsSessionRepository
  2. 请求处理

    • 当客户端发送请求时,SessionRepositoryFilter 会拦截该请求。
    • SessionRepositoryFilter 通过 DefaultSessionIdResolver 获取客户端传来的 Session ID。
    • 如果客户端没有提供 Session ID(首次访问或 Session 过期),则 DefaultSessionIdCreator 会创建一个新的 Session ID。
    • SessionRepositoryFilter 通过 SessionRepository 从 Redis 中加载或创建一个新的 Session。
    • Session 被封装为 DefaultSession 对象,并与请求关联起来。
  3. Session 操作

    • 控制器可以像使用标准的 HttpSession 一样使用 DefaultSession
    • 对 Session 的任何修改都会被记录下来,以便稍后保存到 Redis 中。
  4. Session 保存

    • 当请求结束时,SessionRepositoryFilter 会检测到 Session 是否有变更。
    • 如果 Session 有变更,则会调用 SessionRepositorysave 方法将 Session 保存到 Redis 中。
    • 如果 Session 没有变更,则不会执行保存操作。
  5. Session 无效

    • 如果 Session 过期或被标记为无效,SessionRepository 会将其从 Redis 中删除。

源码分析

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 共享的问题,还保证了应用的可伸缩性和高可用性。

因篇幅问题不能全部显示,请点此查看更多更全内容

Top