1. 概述

在本教程中,我们将介绍如何在 Spring Boot 和非 Spring Boot 项目中使用 Spring Session 并以 MongoDB 作为 Session 存储后端。

Spring Session 支持多种 Session 存储方式,包括 Redis、JDBC 和本例中的 MongoDB。使用 MongoDB 作为 Session 存储非常适合分布式系统,因为 MongoDB 是一个高性能、可扩展的文档数据库。

2. Spring Boot 配置

首先,我们来看一下在 Spring Boot 项目中如何配置 MongoDB 作为 Session 存储。

需要添加如下两个依赖:

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-mongodb</artifactId>
    <version>3.1.5</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
    <version>3.1.5</version>
</dependency>

如果你的项目中引入了多个 Spring Session 模块,你可能需要在 application.properties 中指定使用哪个模块作为 Session 存储:

spring.session.store-type=mongodb

⚠️ 从 Spring Boot 3.0.0 开始,spring.session.store-type 属性已被弃用。Session 存储方式现在由注解和配置类决定。

3. 非 Spring Boot 项目的 Spring 配置

如果你没有使用 Spring Boot,同样可以使用 MongoDB 存储 Session,但需要手动配置。

需要添加如下两个依赖:

<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-mongodb</artifactId>
    <version>3.1.5</version>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>3.1.5</version>
</dependency>

然后通过 Java 配置类启用 MongoDB Session:

@EnableMongoHttpSession
public class HttpSessionConfig {

    @Bean
    public JdkMongoSessionConverter jdkMongoSessionConverter() {
        return new JdkMongoSessionConverter(Duration.ofMinutes(30));
    }
}

@EnableMongoHttpSession 注解会自动配置将 Session 数据存储到 MongoDB 所需的组件。

JdkMongoSessionConverter 负责 Session 数据的序列化和反序列化。

4. 示例应用

我们创建一个简单的 Web 应用用于测试 Session 是否成功存储到 MongoDB。

使用 Spring Boot 的话,只需创建一个 Controller:

@RestController
public class SpringSessionMongoDBController {

    @GetMapping("/")
    public ResponseEntity<Integer> count(HttpSession session) {

        Integer counter = (Integer) session.getAttribute("count");

        if (counter == null) {
            counter = 1;
        } else {
            counter++;
        }

        session.setAttribute("count", counter);

        return ResponseEntity.ok(counter);
    }
}

✅ 每次访问 / 接口时,counter 会递增,并保存在 Session 中。

5. 测试应用

我们可以通过访问接口并检查返回的 Cookie,再使用 Session ID 查询 MongoDB 来验证 Session 是否被正确存储。

示例测试代码如下:

@Test
public void 
  givenEndpointIsCalledTwiceAndResponseIsReturned_whenMongoDBIsQueriedForCount_thenCountMustBeSame() {
    
    HttpEntity<String> response = restTemplate
      .exchange("http://localhost:" + 8080, HttpMethod.GET, null, String.class);
    HttpHeaders headers = response.getHeaders();
    String set_cookie = headers.getFirst(HttpHeaders.SET_COOKIE);

    Assert.assertEquals(response.getBody(),
      repository.findById(getSessionId(set_cookie)).getAttribute("count").toString());
}

private String getSessionId(String cookie) {
    return new String(Base64.getDecoder().decode(cookie.split(";")[0].split("=")[1]));
}

✅ 上述测试会验证 MongoDB 中存储的 Session 数据是否与接口返回的计数一致。

6. 工作原理

Spring Session 的核心组件是 SessionRepositoryFilter,它负责:

  • HttpSession 转换为 MongoSession
  • 检查是否有 Cookie,如有则从存储中加载 Session 数据
  • 将更新后的 Session 数据保存回存储
  • 校验 Session 的有效性

此外,SessionRepositoryFilter 会生成一个名为 SESSION 的 Cookie,该 Cookie 是 HttpOnly 且安全的,其中包含的是 Base64 编码的 Session ID。

✅ 如果你想自定义 Cookie 名称或属性,可以定义一个 DefaultCookieSerializer Bean:

@Bean
public DefaultCookieSerializer customCookieSerializer(){
    DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        
    cookieSerializer.setUseHttpOnlyCookie(false);
        
    return cookieSerializer;
}

7. MongoDB 中存储的 Session 数据

你可以使用如下命令在 MongoDB 中查询 Session 数据:

db.sessions.findOne()

返回结果如下所示:

{
    "_id" : "5d985be4-217c-472c-ae02-d6fca454662b",
    "created" : ISODate("2019-05-14T16:45:41.021Z"),
    "accessed" : ISODate("2019-05-14T17:18:59.118Z"),
    "interval" : "PT30M",
    "principal" : null,
    "expireAt" : ISODate("2019-05-14T17:48:59.118Z"),
    "attr" : BinData(0,"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABdAAFY291bnRzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAC3g=")
}

_id 字段是 Session ID,会被 Base64 编码后作为 Cookie 的值。 ✅ attr 字段存储的是 Session 的实际数据(如本例中的 count)。

8. 总结

本教程介绍了如何使用 Spring Session 与 MongoDB 结合实现 Session 的持久化存储。这种方式非常适合用于分布式系统中 Session 共享的场景。

主要优势包括:

  • ✅ 分布式部署时,多个服务实例可共享 Session
  • ✅ Session 数据持久化,重启服务不丢失
  • ✅ 配置简单,集成灵活

完整源码可参考:GitHub 项目地址


原始标题:Spring Session with MongoDB