如何在Spring Boot应用中使用Redis实现分布式Session
一、背景
在微服务或集群部署场景下,传统的内存式 HTTP Session 无法在多实例间共享,会导致同一用户在不同实例上重复登录。
那么,就可以借助 Redis 作为统一的 Session 存储,实现分布式 Session,并结合自定义拦截器(HandlerInterceptor)在每次请求时校验用户登录状态。
二、为什么用Redis
单实例模式:Session 存储在单机内存,性能快,但无法横向扩展。
集群模式:若不开启 Session 复制,每台机器维护自己的内存 Session,用户在切换实例后 Session 丢失;若使用 Tomcat Session 复制,网络开销大、维护成本高。
三、方案概述
1、Redis 统一存储:所有实例将 Session 数据读写到 Redis,保证各实例共享同一份 Session。
2、Spring Session 集成:使用 Spring Session + Spring Data Redis,无侵入地替换容器原生 Session。
3、自定义拦截器:实现 HandlerInterceptor,在每次请求到达 Controller 之前,从 Session 中获取用户信息,若未登录则重定向到登录页。
HTTP Session图 (转载出处:HTTP Session图)

-
客户端第一次访问,服务端创建一个
HttpSession,生成唯一 ID(JSESSIONID),并通过 Cookie 返回给客户端。 -
客户端后续请求带上该 Cookie,服务端根据 ID 查找并返回对应 Session 对象。
-
我们发现:默认 Session 存储在容器内存,跨实例无法共享
解决方案:Redis 存储 Session 原理
-
Spring Session 将原生
HttpSession接口的实现替换为RedisOperationsSessionRepository -
每次
session.setAttribute(...),会把属性序列化写入 Redis -
请求进来时,通过
sessionId从 Redis 读取并反序列化,还原成HttpSession -
集群中所有实例都连接同一 Redis,实现共享
四、实施步骤
1、环境准备
JDK 1.8以上、Spring Boot 2以上、Spring Session Data Redis、Redis
2、导入依赖
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Session + Redis -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!-- Spring Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
3、Rdis连接
spring:
redis:
host: localhost
port: 6379
session:
store-type: redis # 启用 Redis 存储 Session
timeout: 1800s # Session 过期时间
4、Redis配置
Spring Boot 自动装配了 RedisConnectionFactory 和 RedisTemplate,可自定义序列化策略:
@Configuration
public class RedisConfig {
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
// 使用 JSON 序列化,避免 JDK 序列化导致的可读性差
return new GenericJackson2JsonRedisSerializer();
}
@Bean
public RedisSerializer<Object> defaultRedisSerializer() {
return new StringRedisSerializer();
}
}
5、启用 Spring Session
指定 Session 前缀和超时时间:
@EnableRedisHttpSession(
maxInactiveIntervalInSeconds = 1800, // 30 分钟
redisNamespace = "myapp:sessions" // Redis Key 前缀
)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
6、自定义登录拦截器
实现 HandlerInterceptor,在请求前校验用户是否已登录
@Component
public class LoginInterceptor implements HandlerInterceptor {
// 不拦截的白名单 private static final List<String> WHITELIST = Arrays.asList(
"/login", "/register", "/css/", "/js/"
);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String path = request.getRequestURI();
// 放行白名单
for (String prefix : WHITELIST) {
if (path.startsWith(prefix)) {
return true;
}
}
// 从 Session 中获取用户信息
HttpSession session = request.getSession(false);
if (session != null && session.getAttribute("user") != null) {
// 已登录,继续请求
return true;
}
// 未登录,返回 401 或重定向
if (isAjax(request)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Unauthorized");
} else {
response.sendRedirect("/login");
}
return false;
}
private boolean isAjax(HttpServletRequest request) {
String header = request.getHeader("X-Requested-With");
return "XMLHttpRequest".equals(header);
}
}
7、拦截器注册
将拦截器加入 Spring MVC 拦截链
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**"); // 拦截所有请求
}
}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)