Spring Session - WebSocket

このガイドでは、Spring Session を使用して、WebSocket メッセージが HttpSession を存続させる方法について説明します。

Spring Session の WebSocket サポートは、Spring の WebSocket サポートでのみ機能します。具体的には、JSR-356 には受信 WebSocket メッセージをインターセプトするメカニズムがないため、JSR-356 (英語) を直接使用しても機能しません。

HttpSession セットアップ

最初のステップは、Spring Session を HttpSession と統合することです。これらの手順は、Redis を使用した HttpSession のガイドですでに概説されています。

続行する前に、Spring Session が HttpSession と統合されていることを確認してください。

Spring の設定

典型的な Spring WebSocket アプリケーションでは、WebSocketMessageBrokerConfigurer を実装します。例: 構成は次のようになります。

@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("/messages").withSockJS();
	}

	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		registry.enableSimpleBroker("/queue/", "/topic/");
		registry.setApplicationDestinationPrefixes("/app");
	}

}

Spring Session の WebSocket サポートを使用するように構成を更新できます。次の例は、その方法を示しています。

src/main/java/samples/config/WebSocketConfig.java
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<Session> { (1)

	@Override
	protected void configureStompEndpoints(StompEndpointRegistry registry) { (2)
		registry.addEndpoint("/messages").withSockJS();
	}

	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		registry.enableSimpleBroker("/queue/", "/topic/");
		registry.setApplicationDestinationPrefixes("/app");
	}

}

Spring Session サポートをフックするには、次の 2 つを変更するだけです。

1WebSocketMessageBrokerConfigurer を実装する代わりに、AbstractSessionWebSocketMessageBrokerConfigurer を継承します
2registerStompEndpoints メソッドの名前を configureStompEndpoints に変更します

AbstractSessionWebSocketMessageBrokerConfigurer はバックグラウンドで何をしますか?

  • WebSocketConnectHandlerDecoratorFactory は WebSocketHandlerDecoratorFactory として WebSocketTransportRegistration に追加されます。これにより、WebSocketSession を含むカスタム SessionConnectEvent が確実に起動されます。WebSocketSession は、Spring Session が終了したときにまだ開いている WebSocket 接続を終了するために必要です。

  • SessionRepositoryMessageInterceptor は、すべての StompWebSocketEndpointRegistration に HandshakeInterceptor として追加されます。これにより、Session が WebSocket プロパティに追加され、最終アクセス時刻を更新できるようになります。

  • SessionRepositoryMessageInterceptor は、ChannelInterceptor として受信 ChannelRegistration に追加されます。これにより、受信メッセージを受信するたびに、Spring Session の最終アクセス時刻が更新されます。

  • WebSocketRegistryListener は Spring Bean として作成されます。これにより、すべての Session ID が対応する WebSocket 接続に確実にマッピングされます。このマッピングを維持することにより、Spring Session(HttpSession)が終了したときに、すべての WebSocket 接続を閉じることができます。

websocket サンプルアプリケーション

websocket サンプルアプリケーションは、Spring Session を WebSockets とともに使用する方法を示しています。

websocket サンプルアプリケーションの実行

サンプルを実行するには、ソースコードを取得し、次のコマンドを呼び出します。

$ ./gradlew :spring-session-sample-boot-websocket:bootRun

セッションの有効期限をテストする目的で、アプリケーションを起動する前に次の構成プロパティを追加して、セッションの有効期限を 1 分(デフォルトは 30 分)に変更することをお勧めします。

src/main/resources/application.properties
server.servlet.session.timeout=1m # Session timeout. If a duration suffix is not specified, seconds will be used.
サンプルを機能させるには、ローカルホストで Redis 2.8+ をインストールします (英語) を実行し、デフォルトのポート (6379) で実行する必要があります。または、Redis サーバーを指すように RedisConnectionFactory を更新することもできます。もう 1 つのオプションは、Docker (英語) を使用してローカルホストで Redis を実行することです。詳細な手順については、Docker Redis リポジトリ (英語) を参照してください。

これで、localhost:8080/ でアプリケーションにアクセスできるようになります。

websocket サンプルアプリケーションの探索

これで、アプリケーションを使用してみることができます。次の情報で認証します。

  • ユーザー名 rob

  • パスワード password

次に、ログインボタンをクリックします。これで、ユーザー rob として認証されるはずです。

シークレットウィンドウを開き、localhost:8080/ にアクセスします

ログインフォームが表示されます。次の情報で認証します。

  • ユーザー名 luke

  • パスワード password

次に、rob から luke にメッセージを送信します。メッセージが表示されます。

2 分間待ってから、rob から luke にメッセージを送信してみてください。メッセージが送信されなくなったことがわかります。

なぜ 2 分?

Spring Session は 60 秒で期限切れになりますが、Redis からの通知が 60 秒以内に発生することは保証されていません。ソケットが妥当な時間内に閉じられるようにするために、Spring Session は毎分 00 秒にバックグラウンドタスクを実行し、期限切れのセッションを強制的にクリーンアップします。これは、WebSocket 接続が閉じられるまで最大 2 分待つ必要があることを意味します。

これで、localhost:8080/ へのアクセスを試すことができます。再度認証するように求められます。これは、セッションが適切に期限切れになることを示しています。

ここで同じ演習を繰り返しますが、2 分待つ代わりに、30 秒ごとに各ユーザーからメッセージを送信します。メッセージが引き続き送信されていることがわかります。localhost:8080/ にアクセスしてみてください。再度認証するように求められることはありません。これは、セッションが存続していることを示しています。

ユーザーから送信されたメッセージのみがセッションを存続させます。これは、ユーザーからのメッセージのみがユーザーアクティビティを意味するためです。受信したメッセージはアクティビティを意味しないため、セッションの有効期限を更新しません。