Spring MVCのセッションオブジェクト管理の調査
layers Dev/Java/Spring Boot
label
Java
label
Spring Boot
label
Spring Session
label
Redis
date_range
更新日時 : 2021/03/13 11:04 date_range
投稿日時 : 2021/03/13 10:59概要
厳密にはSpring Sessionだが、業務でSpring MVC+Redisを使用したWebアプリを開発していて、Controllerクラスのセッションに関する動作を検証した。
- Spring MVC+Redisを使用
SessionAttributesアノテーションでセッションオブジェクトを管理- 特定動作完了後にセッション中のオブジェクトを削除またはセッションを破棄する
用意したクラス
UserControllerUserFormオブジェクトをSessionで管理する@SessionAttributesを付与
UserNextControllerUserFormオブジェクトをSessionで管理するが、値設定はしない@SessionAttributesを付与
UserSessionCompleteController@SessionAttributesを付与しない
実行するメソッド
org.springframework.web.bind.support.SessionStatus.setComplete- Session中のオブジェクトを明示的に削除する
javax.servlet.http.HttpSession.invalidate- Sessionを明示的に破棄する
application.propertiesの設定値
デフォルトのまま
| キー | デフォルト値 | 説明 |
|---|---|---|
| spring.session.redis.configure-action | notify-keyspace-events | ユーザー定義の ConfigureRedisAction Bean が存在しない場合に適用する構成アクション。 |
| spring.session.redis.flush-mode | on-save | セッションフラッシュモード。セッションの変更をセッションストアに書き込むタイミングを決定します。 |
| spring.session.redis.namespace | spring:session | セッションの保存に使用されるキーの名前空間。 |
| spring.session.redis.save-mode | on-set-attribute | セッション保存モード。セッションの変更を追跡し、セッションストアに保存する方法を決定します。 |
UserController
- 同じController内での画面制御結果
セッションオブジェクトの削除
| setCompleteパターン | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 画面遷移 | /user/input | /user/detail | /user/complete | /user/detail |
| 画面説明 | 入力フォーム | 入力値表示 | 同ControllerでsessionState.setComplete | 入力値表示 |
| セッションID | X | X | X | X |
| formの値(初期をAとする) | A | A | A | formオブジェクトが取得できない |
- セッションIDは変更されない
- セッションオブジェクトであるUserFormが削除され、
HttpSessionRequiredExceptionが発生する
セッションの削除
| invalidateパターン | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 画面遷移 | /user/input | /user/detail | /user/next/discard | /user/detail |
| 画面説明 | 入力フォーム | 入力値表示 | 別Controllerでsession.invalidate | 入力値表示 |
| セッションID | X | X | X | Y |
| formの値(初期をAとする) | A | A | A | A |
- セッションIDが変更される
- セッションオブジェクトはID変更後も保持される
UserNextController
- 同じセッションオブジェクトを
@SessionAttributesに設定した別クラスでの画面制御結果 - 結果は
UserControllerと変わらず
セッションオブジェクトの削除
| setCompleteパターン | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 画面遷移 | /user/input | /user/detail | /user/next/complete | /user/detail |
| 画面説明 | 入力フォーム | 入力値表示 | 同ControllerでsessionState.setComplete | 入力値表示 |
| セッションID | X | X | X | X |
| formの値(初期をAとする) | A | A | A | formオブジェクトが取得できない |
- セッションIDは変更されない
- セッションオブジェクトであるUserFormが削除され、
HttpSessionRequiredExceptionが発生する
セッションの削除
| invalidateパターン | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 画面遷移 | /user/input | /user/detail | /user/next/discard | /user/detail |
| 画面説明 | 入力フォーム | 入力値表示 | 別Controllerでsession.invalidate | 入力値表示 |
| セッションID | X | X | X | Y |
| formの値(初期をAとする) | A | A | A | A |
- セッションIDが変更される
- セッションオブジェクトはID変更後も保持される
UserSessionCompleteController
@SessionAttributesに設定しない別クラスでの画面制御結果- 同クラス内でsessionCompleteしてもセッションオブジェクトは削除されない
- 同クラス内でinvalidateすると、セッションID変更とオブジェクトも削除される
- 上記結果と異なり、オブジェクトは新しいセッションに引き継がれない
セッションオブジェクトの削除
| setCompleteパターン | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 画面遷移 | /user/input | /user/detail | /user/session/complete | /user/detail |
| 画面説明 | 入力フォーム | 入力値表示 | 別ControllerでsessionState.setComplete | 入力値表示 |
| セッションID | X | X | X | X |
| formの値(初期をAとする) | A | A | formオブジェクトが取得できない | A |
| 画面説明 | 入力フォーム | 入力値表示 | 別ControllerでsessionState.setComplete | 入力値表示 |
- セッションIDは変更されない
- セッションオブジェクトも削除されず、残ったまま
セッションの削除
| invalidateパターン | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 画面遷移 | /user/input | /user/detail | /user/next/discard | /user/detail |
| 画面説明 | 入力フォーム | 入力値表示 | 別Controllerでsession.invalidate | 入力値表示 |
| セッションID | X | X | X | Y |
| formの値(初期をAとする) | A | A | formオブジェクトが取得できない | formオブジェクトが取得できない |
- セッションIDが変更される
- セッションオブジェクトも削除される
HttpSessionRequiredExceptionが発生する
まとめ
@SessionAttributesを付与したクラス内でHttpSession.invalidateメソッドを呼び出してもセッション中のオブジェクトは削除されず、sessionIdが変更されてオブジェクトは残ったままとなる@SessionAttributesを付与したクラス内でSessionStatus.setCompleteを実行すると、削除される。@SessionAttributesを付与していないクラスでHttpSession.invalidateを実行すると、セッションIDの書き換えとともにオブジェクトも削除される
個人的には1.と3.について実装でハマる可能性があるかなと感じた。本来Spring MVC利用していて、HttpSessionを直接操作すること自体は減らす必要があるが、もし必要になった場合は参考にしてほしい。