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 サポートを使用するように構成を更新できます。次の例は、その方法を示しています。
@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 つを変更するだけです。
1 | WebSocketMessageBrokerConfigurer を実装する代わりに、AbstractSessionWebSocketMessageBrokerConfigurer を継承します |
2 | registerStompEndpoints メソッドの名前を 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/ にアクセスしてみてください。再度認証するように求められることはありません。これは、セッションが存続していることを示しています。
ユーザーから送信されたメッセージのみがセッションを存続させます。これは、ユーザーからのメッセージのみがユーザーアクティビティを意味するためです。受信したメッセージはアクティビティを意味しないため、セッションの有効期限を更新しません。 |