Spring でのセッション
SpringではJava ServletのHttpSessionの仕組みを利用することができます。ServletのHttpSessionはSpringフレームワークの上に構築されたアプリケーション上でそのまま利用できるほか、Springの各種ライブラリによってラッピングされた形でも利用することができます。
アプリケーションサーバを複数台構成とした場合のセッション
特に設定を行わなかった場合、Servletのセッションはメモリ上で管理されます。もし複数台のサーバや複数のクラウド上インスタンスにアプリケーションがデプロイされていると、各インスタンス間で個別のメモリ領域を持つことになり、互いにセッションの情報が共有されません。そのため、例えばあるインスタンス上アプリケーションでログインに成功したユーザが、別のインスタンス上アプリにアクセスすると未ログイン状態として扱われてしまう・・・といったことが起こります。
このような問題に対する解決策はいくつかあるのですが、今回はDB上にセッション情報を保存する方法を紹介します。
適用方法
今回はDBMSとしてDb2を使用します。 またSpringアプリケーションのビルドツールとしてGradleを利用し、 すでにDBMSへの接続は完了しているものとします。
Spring Sessionの導入
セッションの管理をDB上で行えるようにします。
build.gradle
に下記パッケージを追加します。
dependencies { .... implementation('org.springframework.boot:spring-boot-starter-web') implementation('org.springframework.boot:spring-boot-starter-data-jpa') implementation("org.springframework.session:spring-session-core") implementation("org.springframework.session:spring-session-jdbc") .... }
Configuration Beanクラスの定義
@EnableJdbcHttpSession
アノテーションを付加した Config
クラスを定義します。これにより、JDBC経由でDB上でセッションを管理できるようになります。
import javax.sql.DataSource; import org.springframework.context.annotation.Bean; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession; import org.springframework.transaction.PlatformTransactionManager; /** * * <p> * セッション情報をJDBC経由でDB上で管理するためのConfiguration * </p> * */ @EnableJdbcHttpSession public class JdbcHttpSessionConfig { @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
Spring設定ファイルの変更
application.properties
に下記項目を追加します。
# Session Setting in DB server.session.jdbc.initialize-schema=always server.session.jdbc.table-name=SPRING_SESSION
application.yml
の場合は以下。
server: sesion: jdbc: initialize-schema: always table-name: SPRING_SESSION
2019/06/02追記
application.yml
application.properties
なしでも動作します。
テーブル名をデフォルトの SPRING_SESSION
から変更したい場合 @EnableJdbcHttpSession
のプロパティ tableName
に値を渡します。
@EnableJdbcHttpSession(tableName = "APP_SESSION")
テーブルの追加
設定は上記で完了なのですが、このままではセッションを保存できません。 既存のDBにセッション情報を追加するテーブルを定義する必要があります。
Spring SessionのGitHubリポジトリにDBMS別のテーブルCREATE用SQLがおいてあるので、こちらを活用しましょう。
ex. Db2の場合(少し編集してあります):
CREATE TABLE SPRING_SESSION ( PRIMARY_ID CHAR(36) NOT NULL, SESSION_ID CHAR(36) NOT NULL, CREATION_TIME BIGINT NOT NULL, LAST_ACCESS_TIME BIGINT NOT NULL, MAX_INACTIVE_INTERVAL INT NOT NULL, EXPIRY_TIME BIGINT NOT NULL, PRINCIPAL_NAME VARCHAR(100), CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) ) ORGANIZE BY ROW; CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME); CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME); CREATE TABLE SPRING_SESSION_ATTRIBUTES ( SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ) ORGANIZE BY ROW;
Db2は列指向*1を定義する機能を持ち、一部データ分析用DBではこの機能がデフォルトになっていたりします(IBM Cloud Db2 Warehouseなど)。この方針のままだと、BLOB
型定義をサポートしていない仕様のため*2、上記SQLでは元のSQLに明示的に ORGANIZE BY ROW
を指定し、メジャーなRDBMS同様の行指向操作がされるようにしています。
2019/06/02追記
@EnableJdbcHttpSession
にてテーブル名を変更した場合、上記SQLでもテーブル名を変更します。
これで、DB上にセッションが保持されるはずです!