中间件:Redis(缓存 / 会话存储)
2026/7/10大约 2 分钟约 704 字
中间件:Redis(缓存 / 会话存储)
1. 简介
Redis 在本项目中专门用作登录会话(Session)的集中存储,替代传统的服务器本地 Session。借助 Redis 的键值存储与 TTL 过期能力,实现分布式、可水平扩展的会话管理,并支持「绝对超时」与「空闲超时」双重策略。项目使用 redis:7-alpine 镜像,开启 AOF 持久化(appendonly yes)。
说明:当前版本 Redis 仅承载会话,未用于业务数据缓存或消息发布订阅。
2. 引入方式
pom.xml 引入 Spring Data Redis 起步依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>3. 配置位置
连接配置:
application.yml的spring.data.redisdata: redis: host: ${REDIS_HOST:localhost} port: ${REDIS_PORT:6379} password: ${REDIS_PASSWORD:} timeout: 3s容器部署:
docker-compose.yml中的redis服务(redis:7-alpine),挂载数据卷redis_data。
4. 在哪里应用
核心使用位于 service/LoginSessionService.java,由 AuthService 在登录、注册时调用,并由 security/ShiroUserRealm.java 在每次请求校验会话时调用。
涉及的类:
LoginSessionService—— 会话的读写与过期管理session/LoginSession.java—— 会话数据载体(record)session/SessionContext.java—— 基于ThreadLocal的当前请求会话上下文AuthService—— 登录/注册创建会话、退出销毁会话
5. 怎么应用(示例)
使用 StringRedisTemplate 以 JSON 字符串形式存储会话,键前缀为 uas:session:,并以「绝对过期时长」作为 Redis 键的 TTL:
private static final String KEY_PREFIX = "uas:session:";
// 创建会话:生成令牌,计算绝对过期时间,写入 Redis(TTL = 绝对超时时长)
public LoginSession create(Long userId, String username, List<String> permissions) {
SysSessionSetting setting = sessionSettingService.requireSetting();
String token = UUID.randomUUID().toString().replace("-", "");
LocalDateTime expiresAt = now.plusMinutes(setting.getAbsoluteTimeoutMinutes());
LoginSession session = new LoginSession(token, userId, username, permissions, now, now, expiresAt);
save(session, Duration.between(now, expiresAt));
return session;
}
// 写入 Redis,并设置 TTL
private void save(LoginSession session, Duration ttl) {
redisTemplate.opsForValue().set(key(session.token()),
objectMapper.writeValueAsString(session), ttl);
}校验与会话续期(validateAndTouch):每次请求携带 Bearer 令牌,先校验绝对过期时间,再校验「最后访问时间 + 空闲超时」是否过期,有效则刷新访问时间并续期。
if (!session.expiresAt().isAfter(now)) { delete(token); return Optional.empty(); }
if (session.lastAccessAt().plusMinutes(setting.getIdleTimeoutMinutes()).isBefore(now)) {
delete(token); return Optional.empty();
}
LoginSession touched = session.touch(now);
save(touched, Duration.between(now, session.expiresAt()));退出登录时直接删除 Redis 键使其失效:
public void logout() {
LoginSession session = SessionContext.current();
if (session != null) loginSessionService.delete(session.token());
}6. 作用是什么
- 集中式会话存储:会话统一放在 Redis,支持多实例部署(任意节点都能校验同一令牌),避免本地 Session 不一致。
- 自动过期:利用 Redis TTL 实现绝对超时,无需后台定时任务清理过期会话。
- 空闲超时控制:结合
sys_session_setting中的idle_timeout_minutes,对长期无操作的会话做二次失效判断。 - 高性能:会话读写均为内存操作,响应快。
7. 相关文件清单
pom.xml(spring-boot-starter-data-redis)src/main/resources/application.yml(spring.data.redis)docker-compose.yml(redis服务)src/main/java/com/yang/backend/service/LoginSessionService.javasrc/main/java/com/yang/backend/service/AuthService.javasrc/main/java/com/yang/backend/session/LoginSession.javasrc/main/java/com/yang/backend/session/SessionContext.java