1. 概要

このクイックチュートリアルでは、Spring Bootを使用する場合と使用しない場合の両方で、MongoDBを使用したSpringSessionの使用方法について説明します。

Spring Sessionは、RedisJDBCなどの他のストアでバックアップすることもできます。

2. スプリングブート構成

まず、Spring Bootに必要な依存関係と構成を見てみましょう。 まず、最新バージョンのspring-session-data-mongodbspring-boot-starter-data-mongodbをプロジェクトに追加しましょう。

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

その後、Spring Boot自動構成を有効にするには、application.propertiesにSpringSessionストアタイプをmongodbとして追加する必要があります。

spring.session.store-type=mongodb

3. スプリングブートなしのスプリング構成

それでは、Spring BootなしでSpringセッションをMongoDBに保存するために必要な依存関係と構成を見てみましょう。

Spring Boot構成と同様に、spring-session-data-mongodb依存関係が必要になります。 ただし、ここではspring-data-mongodb依存関係を使用してMongoDBデータベースにアクセスします。

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

最後に、アプリケーションを構成する方法を見てみましょう。

@EnableMongoHttpSession
public class HttpSessionConfig {

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

@EnableMongoHttpSessionアノテーションは、セッションデータをMongoDBに保存するために必要な構成を有効にします。

また、 JdkMongoSessionConverter は、セッションデータのシリアル化と逆シリアル化を担当することに注意してください。

4. アプリケーション例

構成をテストするためのアプリケーションを作成しましょう。 Spring Bootを使用します。これは、より高速で、必要な構成が少ないためです。

まず、リクエストを処理するコントローラーを作成します。

@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 をインクリメントし、その値をcountという名前のセッション属性に格納しています。

5. アプリケーションのテスト

アプリケーションをテストして、セッションデータを実際にMongoDBに保存できるかどうかを確認しましょう。

そのために、エンドポイントにアクセスし、受信するCookieを検査します。 これにはセッションIDが含まれます。

その後、MongoDBコレクションにクエリを実行して、セッションIDを使用してセッションデータをフェッチします。

@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]));
}

6. それはどのように機能しますか?

舞台裏で春のセッションで何が起こっているのか見てみましょう。

SessionRepositoryFilter は、ほとんどの作業を担当します。

  • HttpSessionMongoSessionに変換します
  • Cookie が存在するかどうかを確認し、存在する場合は、ストアからセッションデータをロードします
  • 更新されたセッションデータをストアに保存します
  • セッションの有効性をチェックします

また、 SessionRepositoryFilter は、HttpOnlyで安全なSESSIONという名前のCookieを作成します。 このCookieには、Base64でエンコードされた値であるセッションIDが含まれています。

Cookieの名前またはプロパティをカスタマイズするには、タイプDefaultCookieSerializer。のSpringBeanを作成する必要があります。

たとえば、ここではCookieのhttponlyプロパティを無効にしています。

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

7. MongoDBに保存されているセッションの詳細

MongoDBコンソールで次のコマンドを使用して、セッションコレクションをクエリしてみましょう。

db.sessions.findOne()

その結果、次のようなBSONドキュメントが得られます。

{
    "_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=")
}

_idUUIDであり、 DefaultCookieSerializer によってBase64でエンコードされ、 SESSIONCookieの値として設定されます。 また、attr属性にはカウンターの実際の値が含まれていることに注意してください。

8. 結論

このチュートリアルでは、分散システムでHTTPセッションを管理するための強力なツールであるMongoDBを利用したSpringSessionについて説明しました。 この目的を念頭に置いて、アプリケーションの複数のインスタンス間でセッションを複製する問題を解決するのに非常に役立ちます。

いつものように、ソースコードはGitHubから入手できます。