Spring Session 的两种解决方案:redis 与 mongodb

  • Spring Session Redis
  • Spring Session MongoDB

Spring Session Redis

在 SpringBoot web 应用程序中,使用 Spring Session 来支持 HttpSession。

1. 添加依赖

1
2
3
4
5
6
7
<dependencies>
......
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
</dependencies>

Spring Boot 为 Spring Session 提供了依赖管理,所以不需要声明依赖的版本。

2. 修改配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Session 的存储方式
spring.session.store-type=redis

# Session 会话超时时间 / 秒
server.servlet.session.timeout=600
# Session 的刷新策略
spring.session.redis.flush-mode=on-save
# 用于存储会话的键名
spring.session.redis.namespace=spring:session

# 连接 Redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=password

spring.session.store-type=redis 相当于手动添加注解 @EnableRedisHttpSession。此操作将会创建一个名为 SpringSessionRepositoryFilter 的过滤器,拦截并替换 SpringSession 支持的 HttpSession 实现。

至此,启动项目并访问项目地址后,用户的 Session 信息存储在 Redis 而不是 Tomcat 的 HttpSession 实现中。

3. 如何工作的

Spring Session 用 Redis 支持的实现来替换 HttpSession。当 Spring Security 的 SecurityContextPersistenceFilter 将 SecurityContext 保存到 HttpSession 时,它将被持久化到 Redis 中。

当一个新的 HttpSession 被创建时,Spring Session 会在你的浏览器中创建一个名为 Session 的 cookie,该 cookie 包含会话的 ID,可以查看 cookies。

参考资料:

  1. Spring Session Redis - DOCS

Spring Session MongoDB

Spring Session MongoDB 提供了一个在 MongoDB 上存储 Session 的 API 和实现。

最低版本要求:

  1. JAVA 8
  2. Servlet 2.5+
  3. Spring 5.0

1. 添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
<dependencies>
......
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-mongodb</artifactId>
<version>${spring-session-data-mongodb.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boo</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>

2. Spring Configuration

增加一个配置类,用于声明 Spring Session 的实现替换 HttpSession 的实现。

1
2
3
4
5
6
7
8
9
10
11
/**
* 创建一个名为 SpringSessionRepositoryFilter 的过滤器
* 负责替换 SpringSession 支持的 HttpSession 实现。
*/
@EnableMongoHttpSession
public class HttpSessionConfig {
@Bean
public JdkMongoSessionConverter jdkMongoSessionConverter() {
return new JdkMongoSessionConverter(Duration.ofMinutes(30));
}
}

为了能在 MongoDB 中持久化 Session 对象,需要提供 序列化与反序列化 机制。默认情况下,使用 JdkMongoSessionConverter

您也可以替换使用 JacksonMongoSessionConverter,或者自定义其实现。

3. 连接 MongoDB

1
2
3
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=test

也可以使用 url 的方式直连:

1
spring.data.mongodb.url=mongodb://localhost:27017/test

4. 如何工作的

Spring Session Redis 一样,将原本在 Tomcat 中的 HttpSession 持久化到 SpringSession 的实现中。

Spring Security 中,SecurityContextPersistenceFilterSecurityContext 保存到 HttpSession 时,他就会被持久化到 Mongo 中。

5. 可能遇到的问题

1. 部分属性序列化失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
@EnableMongoHttpSession
public class SessionConfig {
/**
* 使用 Jackson 进行序列化转换,只需要将转换失败的对象,创建一个对应的 mixin 对象即可
*/
@Bean
public JacksonMongoSessionConverter jdkMongoSessionConverter() {
List<Module> modules = new ArrayList<>();

SimpleModule module = new SimpleModule();
module.setMixInAnnotation(GrantedAuthority.class, GrantedAuthorityMixin.class);

SimpleModule module1 = new SimpleModule();
module1.setMixInAnnotation(LoginUserDetails.class, GrantedAuthorityMixin.class);

modules.add(module);

return new SessionConverter(modules);
}

private static class GrantedAuthorityMixin {}
}

参考资料:

  1. Spring Data Session MongoDB - DOCS
  2. Spring Session MongoDB - DOCS