Spring Session は、ユーザーのセッション情報を管理するための API と実装を提供します。

1. 導入

Spring Session は、ユーザーのセッション情報を管理するための API と実装を提供すると同時に、アプリケーションコンテナー固有のソリューションに縛られることなくクラスター化されたセッションをサポートすることを簡単にします。また、以下との透過的な統合も提供します。

  • HttpSession : アプリケーションコンテナーに依存しない方法で HttpSession を置き換えることができ、RESTfulAPI と連携するためにヘッダーでセッション ID を提供するためのサポートがあります。

  • WebSocket : WebSocket メッセージを受信したときに HttpSession を存続させる機能を提供する

  • WebSession : Spring WebFlux の WebSession を、アプリケーションコンテナーに依存しない方法で置き換えることができます。

2. 2.0 の新機能

次のリストは、Spring Session 2.0: の新機能を示しています。

の変更ログを参照すると、新機能の完全なリストを見つけることができます。

3. サンプルとガイド (ここから開始)

Spring Session の使用を開始するには、サンプルアプリケーションから始めるのが最適です。

表 1: Spring Boot を使用するサンプルアプリケーション
ソース 説明 ガイド

HttpSession と Redis: GitHub (英語)

Spring Session を使用して HttpSession を Redis に置き換える方法を示します。

Redis ガイド付き HttpSession

HttpSession と JDBC: GitHub (英語)

Spring Session を使用して HttpSession をリレーショナルデータベースストアに置き換える方法を示します。

JDBC ガイド付き HttpSession

ユーザー名で検索 : GitHub (英語)

Spring Session を使用してユーザー名でセッションを検索する方法を示します。

ユーザー名ガイドで検索

WebSocket: GitHub (英語)

Spring Session を WebSockets とともに使用する方法を示します。

WebSockets ガイド

WebFlux: GitHub (英語)

Spring Session を使用して Spring を置き換える方法を示します。WebFlux の WebSession を Redis に置き換えます。

RedisJSON 直列化を使用した HttpSession: GitHub (英語)

JSON 直列化を使用して Spring Session を使用して HttpSession を Redis に置き換える方法を示します。

シンプルな Redis を備えた HttpSession SessionRepository: GitHub (英語)

Spring Session を使用して、RedisSessionRepository を使用して HttpSession を Redis に置き換える方法を示します。

テーブル 2: SpringJava ベースの構成を使用するサンプルアプリケーション
ソース 説明 ガイド

HttpSession と Redis: GitHub (英語)

Spring Session を使用して HttpSession を Redis に置き換える方法を示します。

Redis ガイド付き HttpSession

HttpSession と JDBC: GitHub (英語)

Spring Session を使用して HttpSession をリレーショナルデータベースストアに置き換える方法を示します。

JDBC ガイド付き HttpSession

ヘーゼルキャスト付き HttpSession: GitHub (英語)

Spring Session を使用して HttpSession を Hazelcast に置き換える方法を示します。

ヘーゼルキャストガイド付き HttpSession

カスタムクッキー : GitHub (英語)

Spring Session の使用方法と Cookie のカスタマイズ方法を示します。

カスタムクッキーガイド

Spring Security: GitHub (英語)

既存の Spring Security アプリケーションで Spring Session を使用する方法を示します。

Spring Security ガイド

REST: GitHub (英語)

REST アプリケーションで Spring Session を使用して、ヘッダーによる認証をサポートする方法を示します。

REST ガイド

表 3: SpringXML ベースの構成を使用するサンプルアプリケーション
ソース 説明 ガイド

HttpSession と Redis: GitHub (英語)

Spring Session を使用して HttpSession を Redis ストアに置き換える方法を示します。

Redis ガイド付き HttpSession

HttpSession と JDBC: GitHub (英語)

Spring Session を使用して HttpSession をリレーショナルデータベースストアに置き換える方法を示します。

JDBC ガイド付き HttpSession

表 4: その他のサンプルアプリケーション
ソース 説明 ガイド

Hazelcast: GitHub (英語)

Java EE アプリケーションで Hazelcast とともに Spring Session を使用する方法を示します。

4. Spring Session モジュール

Spring Session 1.x, では、Spring Session のすべての SessionRepository 実装が spring-session アーティファクト内で利用可能でした。このアプローチは便利ではありますが、プロジェクトに機能と SessionRepository の実装が追加されたため、長期的には持続可能ではありませんでした。

Spring Session 2.0, 以降、プロジェクトは Spring Session Core モジュールと、特定のデータストアに関連する SessionRepository の実装と機能を実行する他のいくつかのモジュールに分割されます。Spring Data のユーザーは、Spring Session Core モジュールが Spring Data Commons と同等のロールを果たし、コア機能と API を提供し、他のモジュールにはデータストア固有の実装が含まれているため、この配置に慣れているはずです。この分割の一環として、Spring Session データ MongoDB モジュールと Spring Session データ GemFire モジュールは別々のリポジトリに移動されます。現在、プロジェクトのリポジトリ / モジュールの状況は次のとおりです。

最後に、Spring Session は、ユーザーのバージョン管理に関する懸念を支援するために、Maven BOM(「部品表」)モジュールも提供するようになりました。

5. HttpSession 統合

Spring Session は、HttpSession との透過的な統合を提供します。これは、開発者が HttpSession 実装を Spring Session による実装に切り替えることができることを意味します。

5.1. なぜ Spring Session と HttpSession

Spring Session は HttpSession との透過的な統合を提供することはすでに述べましたが、これからどのようなメリットが得られますか?

  • クラスター化されたセッション : Spring Session を使用すると、アプリケーションコンテナー固有のソリューションに縛られることなく、クラスター化されたセッションを簡単にサポートできます。

  • RESTful API : Spring Session を使用すると、ヘッダーでセッション ID を提供できます。RESTful API で機能します。

5.2. Redis を使用した HttpSession 

HttpSession で Spring Session を使用するには、HttpSession を使用するものの前にサーブレットフィルターを追加します。次のいずれかを使用して、これを有効にすることから選択できます。

5.2.1. RedisJava ベースの構成

このセクションでは、Java ベースの構成を使用して Redis を使用して HttpSession をバックアップする方法について説明します。

HttpSession サンプルは、Java 構成を使用して Spring Session と HttpSession を統合する方法の実用的なサンプルを提供します。次のいくつかのセクションで統合の基本的な手順を読むことができますが、独自のアプリケーションと統合する場合は、詳細な HttpSession ガイドに従うことをお勧めします。
Spring Java 構成

必要な依存関係を追加した後、Spring 構成を作成できます。Spring 構成は、HttpSession 実装を Spring Session による実装に置き換えるサーブレットフィルターの作成を担当します。これを行うには、次の Spring 構成を追加します。

@EnableRedisHttpSession (1)
public class Config {

	@Bean
	public LettuceConnectionFactory connectionFactory() {
		return new LettuceConnectionFactory(); (2)
	}

}
1@EnableRedisHttpSession アノテーションは、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成します。このフィルターは、Spring Session によってサポートされる HttpSession 実装の置き換えを担当します。この場合、Spring Session は Redis によってサポートされています。
2Spring Session を Redis サーバーに接続する RedisConnectionFactory を作成します。デフォルトのポート (6379) でローカルホストに接続するように接続を構成します。Spring Data Redis の構成の詳細については、リファレンスドキュメントを参照してください (英語)
Java サーブレットコンテナーの初期化

Spring の設定は、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成しました。springSessionRepositoryFilter Bean は、HttpSession を Spring Session によるカスタム実装に置き換えるロールを果たします。

Filter がその魔法を実行するために、Spring は Config クラスをロードする必要があります。最後に、サーブレットコンテナー(つまり、Tomcat)がすべてのリクエストに springSessionRepositoryFilter を使用するようにする必要があります。幸い、Spring Session は、AbstractHttpSessionApplicationInitializer という名前のユーティリティクラスを提供して、これらの両方の手順を簡単にします。次に例を示します。

src/main/java/sample/Initializer.java
public class Initializer extends AbstractHttpSessionApplicationInitializer { (1)

	public Initializer() {
		super(Config.class); (2)
	}

}
クラスの名前(Initializer)は関係ありません。重要なのは、AbstractHttpSessionApplicationInitializer を継承することです。
1 最初のステップは、AbstractHttpSessionApplicationInitializer を継承することです。そうすることで、springSessionRepositoryFilter という名前の Spring Bean がすべてのリクエストに対してサーブレットコンテナーに登録されます。
2AbstractHttpSessionApplicationInitializer は、Spring が Config を確実にロードするためのメカニズムも提供します。

5.2.2. RedisXML ベースの構成

このセクションでは、Redis を使用して、XML ベースの構成を使用して HttpSession をバックアップする方法について説明します。

HttpSessionXML サンプルは、XML 構成を使用して Spring Session と HttpSession を統合する方法の実用的なサンプルを提供します。次のいくつかのセクションで統合の基本的な手順を読むことができますが、独自のアプリケーションと統合する場合は、詳細な HttpSessionXML ガイドに従うことをお勧めします。
Spring XML 設定

必要な依存関係を追加した後、Spring 構成を作成できます。Spring 構成は、HttpSession 実装を Spring Session による実装に置き換えるサーブレットフィルターの作成を担当します。これを行うには、次の Spring 構成を追加します。

src/main/webapp/WEB-INF/spring/session.xml
(1)
<context:annotation-config/>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>

(2)
<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
1Spring Session はまだ XML 名前空間のサポートを提供していないため、<context:annotation-config/> と RedisHttpSessionConfiguration の組み合わせを使用します(gh-104: GitHub (英語) を参照)。これにより、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean が作成されます。このフィルターは、Spring Session によってサポートされる HttpSession 実装の置き換えを担当します。この場合、Spring Session は Redis によってサポートされています。
2Spring Session を Redis サーバーに接続する RedisConnectionFactory を作成します。デフォルトのポート (6379) でローカルホストに接続するように接続を構成します。Spring Data の構成の詳細については、リファレンスドキュメント (英語) を参照してください。
XML サーブレットコンテナーの初期化

Spring の設定は、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成しました。springSessionRepositoryFilter Bean は、HttpSession を Spring Session によるカスタム実装に置き換えるロールを果たします。

Filter がその魔法を実行するには、Spring に session.xml 構成をロードするように指示する必要があります。これは、次の構成で実行できます。

src/main/webapp/WEB-INF/web.xml
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/spring/session.xml
	</param-value>
</context-param>
<listener>
	<listener-class>
		org.springframework.web.context.ContextLoaderListener
	</listener-class>
</listener>

ContextLoaderListener は contextConfigLocation を読み取り、session.xml 構成を取得します。

最後に、サーブレットコンテナー(つまり、Tomcat)がすべてのリクエストに springSessionRepositoryFilter を使用するようにする必要があります。次のスニペットは、この最後のステップを実行します。

src/main/webapp/WEB-INF/web.xml
<filter>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
	<dispatcher>ERROR</dispatcher>
</filter-mapping>

DelegatingFilterProxy (Javadoc) は、springSessionRepositoryFilter という名前で Bean を検索し、それを Filter にキャストします。DelegatingFilterProxy が呼び出されるすべてのリクエストに対して、springSessionRepositoryFilter が呼び出されます。

5.3. JDBC を使用した HttpSession 

HttpSession を使用するものの前にサーブレットフィルターを追加することにより、HttpSession で Spring Session を使用できます。次のいずれかの方法で実行することを選択できます。

5.3.1. JDBCJava ベースの構成

このセクションでは、Java ベースの構成を使用する場合に、リレーショナルデータベースを使用して HttpSession をバックアップする方法について説明します。

HttpSessionJDBC サンプルは、Java 構成を使用して Spring Session と HttpSession を統合する方法の実用的なサンプルを提供します。次のいくつかのセクションで統合の基本的な手順を読むことができますが、独自のアプリケーションと統合する場合は、詳細な HttpSessionJDBC ガイドに従うことをお勧めします。
Spring Java 構成

必要な依存関係を追加した後、Spring 構成を作成できます。Spring 構成は、HttpSession 実装を Spring Session による実装に置き換えるサーブレットフィルターの作成を担当します。これを行うには、次の Spring 構成を追加します。

@EnableJdbcHttpSession (1)
public class Config {

	@Bean
	public EmbeddedDatabase dataSource() {
		return new EmbeddedDatabaseBuilder() (2)
				.setType(EmbeddedDatabaseType.H2).addScript("org/springframework/session/jdbc/schema-h2.sql").build();
	}

	@Bean
	public PlatformTransactionManager transactionManager(DataSource dataSource) {
		return new DataSourceTransactionManager(dataSource); (3)
	}

}
1@EnableJdbcHttpSession アノテーションは、springSessionRepositoryFilter という名前の Spring Bean を作成します。その Bean は Filter を実装しています。このフィルターは、Spring Session によってサポートされる HttpSession 実装の置き換えを担当します。この場合、Spring Session はリレーショナルデータベースに支えられています。
2Spring Session を H2 データベースの組み込みインスタンスに接続する dataSource を作成します。Spring Session に含まれている SQL スクリプトを使用して、データベーステーブルを作成するように H2 データベースを構成します。
3 以前に構成された dataSource のトランザクションを管理する transactionManager を作成します。

データアクセス関連の懸念事項を構成する方法の詳細については、Spring Framework リファレンスドキュメントを参照してください。

Java サーブレットコンテナーの初期化

Spring の設定は、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成しました。springSessionRepositoryFilter Bean は、HttpSession を Spring Session によるカスタム実装に置き換えるロールを果たします。

Filter がその魔法を実行するために、Spring は Config クラスをロードする必要があります。最後に、サーブレットコンテナー(つまり、Tomcat)がすべてのリクエストに springSessionRepositoryFilter を使用するようにする必要があります。幸い、Spring Session は、AbstractHttpSessionApplicationInitializer という名前のユーティリティクラスを提供して、これらの両方の手順を簡単にします。次の例は、その方法を示しています。

src/main/java/sample/Initializer.java
public class Initializer extends AbstractHttpSessionApplicationInitializer { (1)

	public Initializer() {
		super(Config.class); (2)
	}

}
クラス(初期化子)の名前は関係ありません。重要なのは、AbstractHttpSessionApplicationInitializer を継承することです。
1 最初のステップは、AbstractHttpSessionApplicationInitializer を継承することです。そうすることで、springSessionRepositoryFilter という名前の Spring Bean がすべてのリクエストに対してサーブレットコンテナーに登録されます。
2AbstractHttpSessionApplicationInitializer は、Spring が Config を確実にロードするためのメカニズムも提供します。

5.3.2. JDBCXML ベースの構成

このセクションでは、XML ベースの構成を使用する場合に、リレーショナルデータベースを使用して HttpSession をバックアップする方法について説明します。

HttpSession JDBCXML サンプルは、XML 構成を使用して Spring Session と HttpSession を統合する方法の実用的なサンプルを提供します。次のいくつかのセクションで統合の基本的な手順を読むことができますが、独自のアプリケーションと統合する場合は、詳細な HttpSession JDBCXML ガイドに従うことをお勧めします。
Spring XML 設定

必要な依存関係を追加した後、Spring 構成を作成できます。Spring 構成は、HttpSession 実装を Spring Session による実装に置き換えるサーブレットフィルターの作成を担当します。次のリストは、次の Spring 構成を追加する方法を示しています。

src/main/webapp/WEB-INF/spring/session.xml
(1)
<context:annotation-config/>
<bean class="org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration"/>

(2)
<jdbc:embedded-database id="dataSource" database-name="testdb" type="H2">
	<jdbc:script location="classpath:org/springframework/session/jdbc/schema-h2.sql"/>
</jdbc:embedded-database>

(3)
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<constructor-arg ref="dataSource"/>
</bean>
1Spring Session はまだ XML 名前空間のサポートを提供していないため、<context:annotation-config/> と JdbcHttpSessionConfiguration の組み合わせを使用します(gh-104: GitHub (英語) を参照)。これにより、springSessionRepositoryFilter という名前の Spring Bean が作成されます。その Bean は Filter を実装しています。このフィルターは、Spring Session によってサポートされる HttpSession 実装の置き換えを担当します。この場合、Spring Session はリレーショナルデータベースに支えられています。
2Spring Session を H2 データベースの組み込みインスタンスに接続する dataSource を作成します。Spring Session に含まれている SQL スクリプトを使用して、データベーステーブルを作成するように H2 データベースを構成します。
3 以前に構成された dataSource のトランザクションを管理する transactionManager を作成します。

データアクセス関連の懸念事項を構成する方法の詳細については、Spring Framework リファレンスドキュメントを参照してください。

XML サーブレットコンテナーの初期化

Spring の設定は、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成しました。springSessionRepositoryFilter Bean は、HttpSession を Spring Session によるカスタム実装に置き換えるロールを果たします。

Filter がその魔法を実行するには、Spring に session.xml 構成をロードするように指示する必要があります。これは、次の構成で行います。

src/main/webapp/WEB-INF/web.xml
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/spring/session.xml
	</param-value>
</context-param>
<listener>
	<listener-class>
		org.springframework.web.context.ContextLoaderListener
	</listener-class>
</listener>

ContextLoaderListener は contextConfigLocation を読み取り、session.xml 構成を取得します。

最後に、サーブレットコンテナー(つまり、Tomcat)がすべてのリクエストに springSessionRepositoryFilter を使用するようにする必要があります。次のスニペットは、この最後のステップを実行します。

src/main/webapp/WEB-INF/web.xml
<filter>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>springSessionRepositoryFilter</filter-name>
	<url-pattern>/*</url-pattern>
	<dispatcher>REQUEST</dispatcher>
	<dispatcher>ERROR</dispatcher>
</filter-mapping>

DelegatingFilterProxy (Javadoc) は、springSessionRepositoryFilter という名前の Bean を検索し、それを Filter にキャストします。DelegatingFilterProxy が呼び出されるすべてのリクエストに対して、springSessionRepositoryFilter が呼び出されます。

5.3.3. JDBCSpring ブートベースの構成

このセクションでは、Spring Boot を使用するときにリレーショナルデータベースを使用して HttpSession をバックアップする方法について説明します。

HttpSession JDBCSpring Boot サンプルは、Spring Boot を使用して Spring Session と HttpSession を統合する方法の実用的なサンプルを提供します。次のいくつかのセクションで統合の基本的な手順を読むことができますが、独自のアプリケーションと統合する場合は、詳細な HttpSession JDBCSpring Boot ガイドに従うことをお勧めします。
Spring Boot の設定

必要な依存関係を追加した後、Spring Boot 構成を作成できます。ファーストクラスの自動構成サポートのおかげで、リレーショナルデータベースによる Spring Session のセットアップは、application.properties に単一の構成プロパティを追加するのと同じくらい簡単です。次のリストは、その方法を示しています。

src/main/resources/application.properties
spring.session.store-type=jdbc # Session store type.

内部的には、Spring Boot は、@EnableJdbcHttpSession アノテーションを手動で追加するのと同等の構成を適用します。これにより、springSessionRepositoryFilter という名前の Spring Bean が作成されます。その Bean は Filter を実装しています。このフィルターは、Spring Session によってサポートされる HttpSession 実装の置き換えを担当します。

application.properties を使用してさらにカスタマイズできます。次のリストは、その方法を示しています。

src/main/resources/application.properties
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds are used.
spring.session.jdbc.initialize-schema=embedded # Database schema initialization mode.
spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/[email protected] (英語)  @[email protected] (英語)  @.sql # Path to the SQL file to use to initialize the database schema.
spring.session.jdbc.table-name=SPRING_SESSION # Name of the database table used to store sessions.

詳細については、Spring Boot ドキュメントの Spring Session の部分を参照してください。

DataSource の構成

Spring Boot は、Spring Session を H2 データベースの組み込みインスタンスに接続する DataSource を自動的に作成します。本番環境では、リレーショナルデータベースを指すように構成を更新する必要があります。例:application.properties に以下を含めることができます。

src/main/resources/application.properties
spring.datasource.url= # JDBC URL of the database.
spring.datasource.username= # Login username of the database.
spring.datasource.password= # Login password of the database.

詳細については、Spring Boot ドキュメントの DataSource を構成する部分を参照してください。

サーブレットコンテナーの初期化

Spring Boot の設定は、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成しました。springSessionRepositoryFilter Bean は、HttpSession を Spring Session によるカスタム実装に置き換えるロールを果たします。

Filter がその魔法を実行するために、Spring は Config クラスをロードする必要があります。最後に、サーブレットコンテナー(つまり、Tomcat)がすべてのリクエストに springSessionRepositoryFilter を使用するようにする必要があります。幸い、Spring Boot がこれらの両方の手順を実行してくれます。

5.4. ヘーゼルキャスト付き HttpSession

HttpSession で Spring Session を使用するには、HttpSession を使用するものの前にサーブレットフィルターを追加します。

このセクションでは、Java ベースの構成を使用して Hazelcast を使用して HttpSession をバックアップする方法について説明します。

HazelcastSpring サンプルは、Java 構成を使用して Spring Session と HttpSession を統合する方法の実用的なサンプルを提供します。次のいくつかのセクションで統合の基本的な手順を読むことができますが、独自のアプリケーションと統合する場合は、詳細な HazelcastSpring ガイドに従うことをお勧めします。

5.4.1. Spring の設定

必要な依存関係を追加した後、Spring 構成を作成できます。Spring 構成は、HttpSession 実装を Spring Session による実装に置き換えるサーブレットフィルターの作成を担当します。これを行うには、次の Spring 構成を追加します。

@EnableHazelcastHttpSession (1)
@Configuration
public class HazelcastHttpSessionConfig {

	@Bean
	public HazelcastInstance hazelcastInstance() {
		Config config = new Config();
		MapAttributeConfig attributeConfig = new MapAttributeConfig()
				.setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
				.setExtractor(PrincipalNameExtractor.class.getName());
		config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) (2)
				.addMapAttributeConfig(attributeConfig).addMapIndexConfig(
						new MapIndexConfig(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false));
		return Hazelcast.newHazelcastInstance(config); (3)
	}

}
1@EnableHazelcastHttpSession アノテーションは、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成します。このフィルターは、Spring Session によってサポートされる HttpSession 実装の置き換えを担当します。この例では、Spring Session は Hazelcast によってサポートされています。
2 プリンシパル名インデックスによるセッションの取得をサポートするには、適切な ValueExtractor を登録する必要があります。Spring Session は、この目的のために PrincipalNameExtractor を提供します。
3Spring Session を Hazelcast に接続する HazelcastInstance を作成します。デフォルトでは、アプリケーションが起動し、Hazelcast の組み込みインスタンスに接続します。Hazelcast の構成の詳細については、リファレンスドキュメント (英語) を参照してください。

5.4.2. サーブレットコンテナーの初期化

Spring の設定は、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成しました。springSessionRepositoryFilter Bean は、HttpSession を Spring Session によるカスタム実装に置き換えるロールを果たします。

Filter がその魔法を実行するために、Spring は SessionConfig クラスをロードする必要があります。このアプリケーションは、SecurityInitializer クラスを使用して Spring 構成を既にロードしているため、SessionConfig クラスをアプリケーションに追加できます。次のリストは、その方法を示しています。

src/main/java/sample/SecurityInitializer.java
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {

	public SecurityInitializer() {
		super(SecurityConfig.class, SessionConfig.class);
	}

}

最後に、サーブレットコンテナー(つまり、Tomcat)がすべてのリクエストに springSessionRepositoryFilter を使用するようにする必要があります。Spring Session の springSessionRepositoryFilter は、Spring Security の springSecurityFilterChain の前に呼び出されることが非常に重要です。そうすることで、Spring Security が使用する HttpSession が Spring Session によって確実にサポートされます。幸い、Spring Session には、これを簡単に実行できる AbstractHttpSessionApplicationInitializer という名前のユーティリティクラスが用意されています。次の例は、その方法を示しています。

src/main/java/sample/Initializer.java
public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
クラスの名前(Initializer)は関係ありません。重要なのは、AbstractHttpSessionApplicationInitializer を継承することです。

AbstractHttpSessionApplicationInitializer を継承することにより、springSessionRepositoryFilter という名前の Spring Bean が、Spring Security の springSecurityFilterChain の前のすべてのリクエストに対してサーブレットコンテナーに登録されるようにします。

5.5. HttpSession 統合の仕組み

幸い、HttpSession と HttpServletRequest (HttpSession を取得するための API)はどちらもインターフェースです。これは、これらの API ごとに独自の実装を提供できることを意味します。

このセクションでは、Spring Session が HttpSession との透過的な統合を提供する方法について説明します。このコンテンツは、内部で何が起こっているのかを理解できるように提供しています。この機能はすでに統合されており、このロジックを自分で実装する必要はありません。

まず、HttpSession のカスタム実装を返すカスタム HttpServletRequest を作成します。次のようになります。

public class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {

	public SessionRepositoryRequestWrapper(HttpServletRequest original) {
		super(original);
	}

	public HttpSession getSession() {
		return getSession(true);
	}

	public HttpSession getSession(boolean createNew) {
		// create an HttpSession implementation from Spring Session
	}

	// ... other methods delegate to the original HttpServletRequest ...
}

HttpSession を返すメソッドはすべてオーバーライドされます。他のすべてのメソッドは HttpServletRequestWrapper によって実装され、元の HttpServletRequest 実装に委譲されます。

SessionRepositoryFilter と呼ばれるサーブレット Filter を使用して、HttpServletRequest 実装を置き換えます。以下の擬似コード:

public class SessionRepositoryFilter implements Filter {

	public doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		SessionRepositoryRequestWrapper customRequest =
			new SessionRepositoryRequestWrapper(httpRequest);

		chain.doFilter(customRequest, response, chain);
	}

	// ...
}

カスタム HttpServletRequest 実装を FilterChain に渡すことにより、Filter の後に呼び出されるすべてのものがカスタム HttpSession 実装を使用するようにします。これは、Spring Session の SessionRepositoryFilter を HttpSession と相互作用するものの前に配置することが重要である理由を浮き彫りにします。

5.6. HttpSession および RESTfulAPI

Spring Session は、セッションをヘッダーで提供することにより、RESTfulAPI と連携できます。

REST サンプルは、REST アプリケーションで Spring Session を使用して、ヘッダーによる認証をサポートする方法の実用的なサンプルを提供します。次のいくつかのセクションで説明する統合の基本的な手順に従うことができますが、独自のアプリケーションと統合する場合は、詳細な REST ガイドに従うことをお勧めします。

5.6.1. Spring の設定

必要な依存関係を追加した後、Spring 構成を作成できます。Spring 構成は、HttpSession 実装を Spring Session による実装に置き換えるサーブレットフィルターの作成を担当します。これを行うには、次の Spring 構成を追加します。

@Configuration
@EnableRedisHttpSession (1)
public class HttpSessionConfig {

	@Bean
	public LettuceConnectionFactory connectionFactory() {
		return new LettuceConnectionFactory(); (2)
	}

	@Bean
	public HttpSessionIdResolver httpSessionIdResolver() {
		return HeaderHttpSessionIdResolver.xAuthToken(); (3)
	}

}
1@EnableRedisHttpSession アノテーションは、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成します。このフィルターは、Spring Session によってサポートされる HttpSession 実装の置き換えを担当します。この場合、Spring Session は Redis によってサポートされています。
2Spring Session を Redis サーバーに接続する RedisConnectionFactory を作成します。デフォルトのポート (6379) でローカルホストに接続するように接続を構成します。Spring Data Redis の構成の詳細については、リファレンスドキュメントを参照してください (英語)
3Spring Session の HttpSession 統合をカスタマイズして、Cookie の代わりに HTTP ヘッダーを使用して現在のセッション情報を伝達します。

5.6.2. サーブレットコンテナーの初期化

Spring の設定は、Filter を実装する springSessionRepositoryFilter という名前の Spring Bean を作成しました。springSessionRepositoryFilter Bean は、HttpSession を Spring Session によるカスタム実装に置き換えるロールを果たします。

Filter がその魔法を実行するために、Spring は Config クラスをロードする必要があります。次の例に示すように、Spring MvcInitializer で構成を提供します。

src/main/java/sample/mvc/MvcInitializer.java
@Override
protected Class<?>[] getRootConfigClasses() {
	return new Class[] { SecurityConfig.class, HttpSessionConfig.class };
}

最後に、サーブレットコンテナー(つまり、Tomcat)がすべてのリクエストに springSessionRepositoryFilter を使用するようにする必要があります。幸い、Spring Session には、AbstractHttpSessionApplicationInitializer という名前のユーティリティクラスが用意されており、これを簡単に実行できます。これを行うには、次の例に示すように、デフォルトのコンストラクターを使用してクラスを継承します。

src/main/java/sample/Initializer.java
public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
クラスの名前(Initializer)は関係ありません。重要なのは、AbstractHttpSessionApplicationInitializer を継承することです。

5.7. HttpSessionListener を使用する

Spring Session は、SessionEventHttpSessionListenerAdapter を宣言することにより、SessionDestroyedEvent および SessionCreatedEvent を HttpSessionEvent に変換することにより、HttpSessionListener をサポートします。このサポートを使用するには、次のことを行う必要があります。

  • SessionRepository 実装が、SessionDestroyedEvent および SessionCreatedEvent を起動するようにサポートおよび構成されていることを確認してください。

  • SessionEventHttpSessionListenerAdapter を Spring Bean として構成します。

  • すべての HttpSessionListener を SessionEventHttpSessionListenerAdapter に注入する

Redis を使用した HttpSession  に記載されている構成サポートを使用する場合は、すべての HttpSessionListener を Bean として登録するだけです。例:Spring Security の同時実行制御をサポートし、HttpSessionEventPublisher を使用する必要があると想定します。その場合、HttpSessionEventPublisher を Bean として追加できます。Java 構成では、これは次のようになります。

@Configuration
@EnableRedisHttpSession
public class RedisHttpSessionConfig {

	@Bean
	public HttpSessionEventPublisher httpSessionEventPublisher() {
		return new HttpSessionEventPublisher();
	}

	// ...

}

XML 構成では、これは次のようになります。

<bean class="org.springframework.security.web.session.HttpSessionEventPublisher"/>

6. WebSocket 統合

Spring Session は、Spring の WebSocket サポートとの透過的な統合を提供します。

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

6.1. なぜ Spring Session と WebSockets なのでしょうか?

では、WebSockets を使用するときになぜ Spring Session が必要なのですか?

HTTP リクエストを介して多くの作業を行うメールアプリケーションについて考えてみます。ただし、WebSocketAPI 上で機能するチャットアプリケーションも組み込まれています。ユーザーが誰かと積極的にチャットしている場合は、HttpSession をタイムアウトしないでください。これは、ユーザーエクスペリエンスがかなり低下するためです。ただし、これはまさに JSR-356 (英語) が行うことです。

もう 1 つの課題は、JSR-356 によると、HttpSession がタイムアウトした場合、その HttpSession と認証されたユーザーで作成された WebSocket を強制的に閉じる必要があることです。つまり、アプリケーションでアクティブにチャットしていて、HttpSession を使用していない場合は、会話からも切断されます。

6.2. WebSocket の使用箇所

WebSocket サンプルは、Spring Session を WebSockets と統合する方法の実用的なサンプルを提供します。次のいくつかの見出しで説明する統合の基本的な手順に従うことができますが、独自のアプリケーションと統合する場合は、詳細な WebSocket ガイドに従うことをお勧めします。

6.2.1. HttpSession 統合

WebSocket 統合を使用する前に、最初に HttpSession 統合が機能していることを確認する必要があります。

6.2.2. 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 接続を閉じることができます。

7. WebSession 統合

Spring Session は、Spring WebFlux の WebSession との透過的な統合を提供します。これは、Spring Session による実装で WebSession 実装を切り替えることができることを意味します。

7.1. なぜ Spring Session と WebSession なのでしょうか?

Spring Session が Spring WebFlux の WebSession との透過的な統合を提供することはすでに述べましたが、これからどのようなメリットが得られますか? HttpSession と同様に、Spring Session を使用すると、アプリケーションコンテナー固有のソリューションに縛られることなく、クラスター化されたセッションを簡単にサポートできます。

7.2. WebSession と Redis

WebSession で Spring Session を使用するには、Spring Session の ReactiveSessionRepository に基づく WebSessionManager 実装を登録します。Spring 構成は、WebSession 実装を Spring Session による実装に置き換える WebSessionManager の作成を担当します。これを行うには、次の Spring 構成を追加します。

@EnableRedisWebSession (1)
public class SessionConfiguration {

	@Bean
	public LettuceConnectionFactory redisConnectionFactory() {
		return new LettuceConnectionFactory(); (2)
	}

}
1@EnableRedisWebSession アノテーションは、webSessionManager という名前の Spring Bean を作成します。その Bean は WebSessionManager を実装します。これは、Spring Session によってサポートされる WebSession 実装の置き換えを担当するものです。この場合、Spring Session は Redis によってサポートされています。
2Spring Session を Redis サーバーに接続する RedisConnectionFactory を作成します。デフォルトのポート (6379) でローカルホストに接続するように接続を構成します。Spring Data の構成の詳細については、リファレンスドキュメント (英語) を参照してください。

7.3. WebSession 統合の仕組み

サーブレット API とその HttpSession と比較して、Spring Session が Spring WebFlux とその WebSession と統合するのはかなり簡単です。Spring WebFlux は、WebSession を永続化するための戦略を提示する WebSessionStore API を提供します。

このセクションでは、Spring Session が WebSession との透過的な統合を提供する方法について説明します。このコンテンツは、内部で何が起こっているのかを理解できるように提供しています。この機能はすでに統合されており、このロジックを自分で実装する必要はありません。

まず、Spring Session の Session に委譲するカスタム SpringSessionWebSession を作成します。次のようになります。

public class SpringSessionWebSession implements WebSession {

	enum State {
		NEW, STARTED
	}

	private final S session;

	private AtomicReference<State> state = new AtomicReference<>();

	SpringSessionWebSession(S session, State state) {
		this.session = session;
		this.state.set(state);
	}

	@Override
	public void start() {
		this.state.compareAndSet(State.NEW, State.STARTED);
	}

	@Override
	public boolean isStarted() {
		State value = this.state.get();
		return (State.STARTED.equals(value)
				|| (State.NEW.equals(value) && !this.session.getAttributes().isEmpty()));
	}

	@Override
	public Mono<Void> changeSessionId() {
		return Mono.defer(() -> {
			this.session.changeSessionId();
			return save();
		});
	}

	// ... other methods delegate to the original Session
}

次に、次のリストに示すように、ReactiveSessionRepository に委譲し、Session をカスタム WebSession 実装にラップするカスタム WebSessionStore を作成します。

public class SpringSessionWebSessionStore<S extends Session> implements WebSessionStore {

	private final ReactiveSessionRepository<S> sessions;

	public SpringSessionWebSessionStore(ReactiveSessionRepository<S> reactiveSessionRepository) {
		this.sessions = reactiveSessionRepository;
	}

	// ...
}

Spring WebFlux によって検出されるためには、このカスタム WebSessionStore は、webSessionManager という名前の Bean として ApplicationContext に登録されている必要があります。Spring WebFlux の詳細については、Spring Framework リファレンスドキュメントを参照してください。

8. Spring Security 統合

Spring Session は Spring Security との統合を提供します。

8.1. Spring Security リメンバーミーサポート

Spring Session は Spring Security の Remember-me 認証との統合を提供します。サポート:

  • セッションの有効期限の長さを変更する

  • セッション Cookie が Integer.MAX_VALUE で期限切れになることを確認します。Cookie はセッションの作成時にのみ設定されるため、Cookie の有効期限は可能な限り最大の値に設定されます。セッションの有効期限と同じ値に設定されている場合、ユーザーが使用したときにセッションが更新されますが、Cookie の有効期限は更新されません(有効期限が修正されるため)。

Java 構成で Spring Security を使用して Spring Session を構成するには、以下のリストをガイドとして使用できます。

@Override
protected void configure(HttpSecurity http) throws Exception {
	http
		// ... additional configuration ...
		.rememberMe()
			.rememberMeServices(rememberMeServices());
}

@Bean
public SpringSessionRememberMeServices rememberMeServices() {
	SpringSessionRememberMeServices rememberMeServices =
			new SpringSessionRememberMeServices();
	// optionally customize
	rememberMeServices.setAlwaysRemember(true);
	return rememberMeServices;
}

XML ベースの構成は次のようになります。

<security:http>
	<!-- ... -->
	<security:form-login />
	<security:remember-me services-ref="rememberMeServices"/>
</security:http>

<bean id="rememberMeServices"
	class="org.springframework.session.security.web.authentication.SpringSessionRememberMeServices"
	p:alwaysRemember="true"/>

8.2. Spring Security 同時セッション制御

Spring Session は、Spring Security との統合を提供して、同時セッション制御をサポートします。これにより、1 人のユーザーが同時に持つことができるアクティブなセッションの数を制限できますが、デフォルトの Spring Security サポートとは異なり、これはクラスター環境でも機能します。これは、Spring Security の SessionRegistry インターフェースのカスタム実装を提供することによって行われます。

Spring Security の Javaconfig DSL を使用する場合、次のリストに示すように、SessionManagementConfigurer を介してカスタム SessionRegistry を構成できます。

@Configuration
public class SecurityConfiguration<S extends Session> extends WebSecurityConfigurerAdapter {

	@Autowired
	private FindByIndexNameSessionRepository<S> sessionRepository;

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// @formatter:off
		http
			// other config goes here...
			.sessionManagement()
				.maximumSessions(2)
				.sessionRegistry(sessionRegistry());
		// @formatter:on
	}

	@Bean
	public SpringSessionBackedSessionRegistry<S> sessionRegistry() {
		return new SpringSessionBackedSessionRegistry<>(this.sessionRepository);
	}

}

これは、Session インスタンスを返す FindByIndexNameSessionRepository を提供するように Spring Session も構成していることを前提としています。

XML 構成を使用すると、次のリストのようになります。

<security:http>
	<!-- other config goes here... -->
	<security:session-management>
		<security:concurrency-control max-sessions="2" session-registry-ref="sessionRegistry"/>
	</security:session-management>
</security:http>

<bean id="sessionRegistry"
	  class="org.springframework.session.security.SpringSessionBackedSessionRegistry">
	<constructor-arg ref="sessionRepository"/>
</bean>

これは、Spring Session SessionRegistry Bean が sessionRegistry と呼ばれることを前提としています。これは、すべての SpringHttpSessionConfiguration サブクラスで使用される名前です。

8.3. 制限

Spring Session の Spring Security の SessionRegistry インターフェースの実装は、Spring Session を使用してこの情報を取得できないため、getAllPrincipals メソッドをサポートしていません。このメソッドは Spring Security によって呼び出されることはないため、これは SessionRegistry 自体にアクセスするアプリケーションにのみ影響します。

9. API ドキュメント

Javadoc 全体をオンラインで閲覧できます。主要な API については、次のセクションで説明します。

9.1. Session を使用する

Session は、名前と値のペアの簡略化された Map です。

一般的な使用箇所は、次のリストのようになります。

public class RepositoryDemo<S extends Session> {

	private SessionRepository<S> repository; (1)

	public void demo() {
		S toSave = this.repository.createSession(); (2)

		(3)
		User rwinch = new User("rwinch");
		toSave.setAttribute(ATTR_USER, rwinch);

		this.repository.save(toSave); (4)

		S session = this.repository.findById(toSave.getId()); (5)

		(6)
		User user = session.getAttribute(ATTR_USER);
		assertThat(user).isEqualTo(rwinch);
	}

	// ... setter methods ...

}
1Session を継承するジェネリック型 S を使用して SessionRepository インスタンスを作成します。ジェネリック型はクラスで定義されています。
2SessionRepository を使用して新しい Session を作成し、それをタイプ S の変数に割り当てます。
3Session と対話します。この例では、User を Session に保存する方法を示します。
4 ここで、Session を保存します。これが、ジェネリック型 S が必要な理由です。SessionRepository では、同じ SessionRepository を使用して作成または取得された Session インスタンスのみを保存できます。これにより、SessionRepository は実装固有の最適化を行うことができます(つまり、変更された属性のみを書き込む)。
5SessionRepository から Session を取得します。
6 属性を明示的にキャストする必要なしに、Session から永続化された User を取得します。

Session API は、Session インスタンスの有効期限に関連する属性も提供します。

一般的な使用箇所は、次のリストのようになります。

public class ExpiringRepositoryDemo<S extends Session> {

	private SessionRepository<S> repository; (1)

	public void demo() {
		S toSave = this.repository.createSession(); (2)
		// ...
		toSave.setMaxInactiveInterval(Duration.ofSeconds(30)); (3)

		this.repository.save(toSave); (4)

		S session = this.repository.findById(toSave.getId()); (5)
		// ...
	}

	// ... setter methods ...

}
1Session を継承するジェネリック型 S を使用して SessionRepository インスタンスを作成します。ジェネリック型はクラスで定義されています。
2SessionRepository を使用して新しい Session を作成し、それをタイプ S の変数に割り当てます。
3Session と対話します。この例では、Session が期限切れになる前に非アクティブにできる時間を更新する方法を示します。
4 ここで、Session を保存します。これが、ジェネリック型 S が必要な理由です。SessionRepository では、同じ SessionRepository を使用して作成または取得された Session インスタンスのみを保存できます。これにより、SessionRepository は実装固有の最適化を行うことができます(つまり、変更された属性のみを書き込む)。最終アクセス時刻は、Session が保存されるときに自動的に更新されます。
5SessionRepository から Session を取得します。Session の有効期限が切れている場合、結果は null になります。

9.2. SessionRepository を使用する

SessionRepository は、Session インスタンスの作成、取得、永続化を担当します。

可能であれば、SessionRepository または Session と直接対話しないでください。代わりに、開発者は HttpSessionWebSocket の統合を通じて間接的に SessionRepository と Session と対話することを好むべきです。

9.3. FindByIndexNameSessionRepository を使用する

Session を使用するための Spring Session の最も基本的な API は SessionRepository です。この API は意図的に非常に単純であるため、基本的な機能を備えた追加の実装を簡単に提供できます。

一部の SessionRepository 実装では、FindByIndexNameSessionRepository の実装を選択する場合もあります。例:Spring の Redis、JDBC、Hazelcast サポートライブラリはすべて FindByIndexNameSessionRepository を実装しています。

FindByIndexNameSessionRepository は、指定されたインデックス名とインデックス値を持つすべてのセッションを検索するメソッドを提供します。提供されているすべての FindByIndexNameSessionRepository 実装でサポートされている一般的な使用例として、便利な方法を使用して、特定のユーザーのすべてのセッションを検索できます。これは、FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME という名前のセッション属性にユーザー名が入力されていることを確認することによって行われます。Spring Session は使用されている認証メカニズムを認識していないため、属性が設定されていることを確認するのはユーザーの責任です。これを使用する方法の例は、次のリストで見ることができます:

String username = "username";
this.session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
FindByIndexNameSessionRepository の一部の実装は、他のセッション属性に自動的にインデックスを付けるためのフックを提供します。例:多くの実装では、現在の Spring Security ユーザー名が FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME のインデックス名でインデックス付けされていることを自動的に確認します。

セッションのインデックスが作成されると、次のようなコードを使用して見つけることができます。

String username = "username";
Map<String, Session> sessionIdToSession = this.sessionRepository.findByPrincipalName(username);

9.4. ReactiveSessionRepository を使用する

ReactiveSessionRepository は、Session インスタンスの作成、取得、永続化をノンブロッキングおよびリアクティブな方法で担当します。

可能であれば、ReactiveSessionRepository または Session と直接対話しないでください。代わりに、WebSession 統合を介して間接的に ReactiveSessionRepository および Session と対話することをお勧めします。

9.5. @EnableSpringHttpSession を使用する

@EnableSpringHttpSession アノテーションを @Configuration クラスに追加して、SessionRepositoryFilter を springSessionRepositoryFilter という名前の Bean として公開できます。アノテーションを使用するには、単一の SessionRepository Bean を提供する必要があります。次の例は、その方法を示しています。

@EnableSpringHttpSession
@Configuration
public class SpringHttpSessionConfig {

	@Bean
	public MapSessionRepository sessionRepository() {
		return new MapSessionRepository(new ConcurrentHashMap<>());
	}

}

セッションの有効期限のインフラストラクチャは構成されていないことに注意してください。これは、セッションの有効期限などが実装に大きく依存するためです。つまり、期限切れのセッションをクリーンアップする必要がある場合は、期限切れのセッションをクリーンアップする責任があります。

9.6. @EnableSpringWebSession を使用する

@EnableSpringWebSession アノテーションを @Configuration クラスに追加して、WebSessionManager を webSessionManager という名前の Bean として公開できます。アノテーションを使用するには、単一の ReactiveSessionRepository Bean を指定する必要があります。次の例は、その方法を示しています。

@EnableSpringWebSession
public class SpringWebSessionConfig {

	@Bean
	public ReactiveSessionRepository reactiveSessionRepository() {
		return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
	}

}

セッションの有効期限のインフラストラクチャは構成されていないことに注意してください。これは、セッションの有効期限などが実装に大きく依存するためです。つまり、期限切れのセッションをクリーンアップする必要がある場合は、期限切れのセッションをクリーンアップする責任があります。

9.7. RedisIndexedSessionRepository を使用する

RedisIndexedSessionRepository は、Spring Data の RedisOperations を使用して実装される SessionRepository です。Web 環境では、これは通常 SessionRepositoryFilter と組み合わせて使用されます。実装は、SessionDestroyedEvent および SessionCreatedEvent から SessionMessageListener をサポートします。

9.7.1. RedisIndexedSessionRepository のインスタンス化

次のリストに、新しいインスタンスを作成する方法の典型的な例を示します。

RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();

// ... configure redisTemplate ...

SessionRepository<? extends Session> repository = new RedisIndexedSessionRepository(redisTemplate);

RedisConnectionFactory の作成方法の詳細については、「Spring Data Redis リファレンス」を参照してください。

9.7.2. @EnableRedisHttpSession を使用する

Web 環境では、新しい RedisIndexedSessionRepository を作成する最も簡単な方法は、@EnableRedisHttpSession を使用することです。完全な使用例はサンプルとガイド (ここから開始) にあります。次の属性を使用して、構成をカスタマイズできます。

  • maxInactiveIntervalInSeconds: セッションが期限切れになるまでの時間(秒単位)。

  • redisNamespace: セッションのアプリケーション固有の名前空間を構成できます。Redis キーとチャネル ID は、プレフィックス <redisNamespace>: で始まります。

  • flushMode: Redis にデータを書き込むタイミングを指定できます。デフォルトは、save が SessionRepository で呼び出された場合のみです。FlushMode.IMMEDIATE の値は、できるだけ早く Redis に書き込みます。

カスタム RedisSerializer

RedisSerializer<Object> を実装する springSessionDefaultRedisSerializer という名前の Bean を作成することにより、直列化をカスタマイズできます。

9.7.3. Redis TaskExecutor

RedisIndexedSessionRepository は、RedisMessageListenerContainer を使用して Redis からイベントを受信するようにサブスクライブされています。springSessionRedisTaskExecutor、Bean springSessionRedisSubscriptionExecutor、またはその両方という名前の Bean を作成することにより、これらのイベントのディスパッチ方法をカスタマイズできます。Redis タスクエグゼキュータの設定の詳細については、こちらを参照してください (英語)

9.7.4. ストレージの詳細

次のセクションでは、操作ごとに Redis がどのように更新されるかについて概説します。次の例は、新しいセッションを作成する例を示しています。

HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 \
	maxInactiveInterval 1800 \
	lastAccessedTime 1404360000000 \
	sessionAttr:attrName someAttrValue \
	sessionAttr2:attrName someAttrValue2
EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
EXPIRE spring:session:expirations1439245080000 2100

以降のセクションでは、詳細について説明します。

セッションの保存

各セッションは、Hash として Redis に保存されます。各セッションは、HMSET コマンドを使用して設定および更新されます。次の例は、各セッションがどのように保存されるかを示しています。

HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 \
	maxInactiveInterval 1800 \
	lastAccessedTime 1404360000000 \
	sessionAttr:attrName someAttrValue \
	sessionAttr2:attrName someAttrValue2

前の例では、セッションについて次のステートメントが当てはまります。

  • セッション ID は 33fdd1b6-b496-4b33-9f7d-df96679d32fe です。

  • セッションは 1404360000000 で作成されました(1/1/1970 GMT の午前 0 時からのミリ秒単位)。

  • セッションは 1800 秒(30 分)で期限切れになります。

  • セッションは 1404360000000 で最後にアクセスされました(1/1/1970 GMT の深夜からのミリ秒単位)。

  • セッションには 2 つの属性があります。1 つ目は attrName で、値は someAttrValue です。2 番目のセッション属性は attrName2 という名前で、値は someAttrValue2 です。

最適化された書き込み

RedisIndexedSessionRepository によって管理される Session インスタンスは、変更されたプロパティを追跡し、それらのみを更新します。つまり、属性が 1 回書き込まれ、何度も読み取られる場合、その属性を 1 回だけ書き込む必要があります。例:前のセクションの lsiting の sessionAttr2 セッション属性が更新されたと想定します。保存時に次のコマンドが実行されます。

HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe sessionAttr:attrName2 newValue
セッションの有効期限

有効期限は、Session.getMaxInactiveInterval() に基づいて EXPIRE コマンドを使用して各セッションに関連付けられます。次の例は、典型的な EXPIRE コマンドを示しています。

EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100

セッションが実際に期限切れになった後、5 分に設定されている有効期限に注意してください。これは、セッションの有効期限が切れたときにセッションの値にアクセスできるようにするために必要です。有効期限は、実際に有効期限が切れてから 5 分後にセッション自体に設定され、確実にクリーンアップされますが、必要な処理を実行した後でのみです。

SessionRepository.findById(String) メソッドは、期限切れのセッションが返されないことを保証します。これは、セッションを使用する前に有効期限を確認する必要がないことを意味します。

Spring Session は、Redis からの削除および期限切れのキースペース通知 (英語) に依存して、それぞれ SessionDeletedEvent および SessionExpiredEvent を起動します。SessionDeletedEvent または SessionExpiredEvent は、Session に関連付けられたリソースが確実にクリーンアップされるようにします。例:Spring Session の WebSocket サポートを使用する場合、Redis の期限切れまたは削除イベントにより、セッションに関連付けられている WebSocket 接続がすべて閉じられます。

有効期限は、セッションキー自体で直接追跡されません。これは、セッションデータが利用できなくなることを意味するためです。代わりに、特別なセッションの有効期限キーが使用されます。前の例では、expires キーは次のとおりです。

APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800

セッションの有効期限が切れるキーが削除または期限切れになると、キースペース通知が実際のセッションのルックアップをトリガーし、SessionDestroyedEvent が起動されます。

Redis の有効期限のみに依存する場合の問題のひとつは、キーにアクセスしていない場合、Redis は期限切れのイベントがいつ発生するかを保証しないことです。具体的には、Redis が期限切れのキーをクリーンアップするために使用するバックグラウンドタスクは優先度の低いタスクであり、キーの期限切れをトリガーしない場合があります。詳細については、Redis ドキュメントの期限切れのイベントのタイミング (英語) セクションを参照してください。

期限切れのイベントが発生することが保証されていないという事実を回避するために、期限切れが予想されるときに各キーにアクセスできるようにすることができます。つまり、キーの TTL が期限切れになると、Redis はキーを削除し、キーにアクセスしようとすると期限切れイベントを発生させます。

このため、各セッションの有効期限も最も近い分まで追跡されます。これにより、バックグラウンドタスクが期限切れの可能性のあるセッションにアクセスして、Redis の期限切れイベントがより決定論的な方法で発生するようになります。次の例は、これらのイベントを示しています。

SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
EXPIRE spring:session:expirations1439245080000 2100

次に、バックグラウンドタスクはこれらのマッピングを使用して、各キーを明示的にリクエストします。キーを削除するのではなくアクセスすることで、TTL が期限切れになった場合にのみ Redis がキーを削除するようにします。

場合によっては、有効期限が切れていないのにキーが期限切れであると誤って識別する競合状態が発生する可能性があるため、キーを明示的に削除しません。分散ロックを使用しないと(パフォーマンスが低下します)、有効期限マッピングの一貫性を確保する方法はありません。キーにアクセスするだけで、そのキーの TTL が期限切れになった場合にのみキーが削除されるようになります。

9.7.5. SessionDeletedEvent および SessionExpiredEvent

SessionDeletedEvent と SessionExpiredEvent はどちらも SessionDestroyedEvent のタイプです。

RedisIndexedSessionRepository は、Session が削除されたときの SessionDeletedEvent の起動、または Session の有効期限が切れたときの SessionExpiredEvent の起動をサポートします。これは、Session に関連するリソースが適切にクリーンアップされるようにするために必要です。

例:WebSockets と統合する場合、SessionDestroyedEvent はアクティブな WebSocket 接続のクローズを担当します。

SessionDeletedEvent または SessionExpiredEvent の発射は、Redis キースペースイベント (英語) をリッスンする SessionMessageListener を介して利用可能になります。これを機能させるには、汎用コマンドおよび期限切れイベントの Redis キースペースイベントを有効にする必要があります。次の例は、その方法を示しています。

redis-cli config set notify-keyspace-events Egx

@EnableRedisHttpSession を使用する場合、SessionMessageListener の管理と、必要な Redis キースペースイベントの有効化は自動的に行われます。ただし、セキュリティで保護された Redis 環境では、config コマンドは無効になっています。これは、Spring Session が Redis キースペースイベントを構成できないことを意味します。自動構成を無効にするには、ConfigureRedisAction.NO_OP を Bean として追加します。

例:Java 構成では、以下を使用できます。

@Bean
ConfigureRedisAction configureRedisAction() {
	return ConfigureRedisAction.NO_OP;
}

XML 構成では、以下を使用できます。

<util:constant
	static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>

9.7.6. SessionCreatedEvent を使用する

セッションが作成されると、イベントは spring:session:channel:created:33fdd1b6-b496-4b33-9f7d-df96679d32fe のチャネル ID で Redis に送信されます。ここで、33fdd1b6-b496-4b33-9f7d-df96679d32fe はセッション ID です。イベントの本体は、作成されたセッションです。

MessageListener (デフォルト)として登録されている場合、RedisIndexedSessionRepository は Redis メッセージを SessionCreatedEvent に変換します。

9.7.7. Redis でのセッションの表示

redis-cli をインストールした (英語) 後、redis-cli (英語) を使用して Redis (英語) の値を調べることができます。例:ターミナルに次のように入力できます。

$ redis-cli
redis 127.0.0.1:6379> keys *
1) "spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021" (1)
2) "spring:session:expirations:1418772300000" (2)
1 このキーのサフィックスは、Spring Session のセッション ID です。
2 このキーには、1418772300000 時に削除する必要があるすべてのセッション ID が含まれています。

各セッションの属性を表示することもできます。次の例は、その方法を示しています。

redis 127.0.0.1:6379> hkeys spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021
1) "lastAccessedTime"
2) "creationTime"
3) "maxInactiveInterval"
4) "sessionAttr:username"
redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021 sessionAttr:username
"\xac\xed\x00\x05t\x00\x03rob"

9.8. ReactiveRedisSessionRepository を使用する

ReactiveRedisSessionRepository は、Spring Data の ReactiveRedisOperations を使用して実装される ReactiveSessionRepository です。Web 環境では、これは通常 WebSessionStore と組み合わせて使用されます。

9.8.1. ReactiveRedisSessionRepository のインスタンス化

次の例は、新しいインスタンスを作成する方法を示しています。

// ... create and configure connectionFactory and serializationContext ...

ReactiveRedisTemplate<String, Object> redisTemplate = new ReactiveRedisTemplate<>(connectionFactory,
		serializationContext);

ReactiveSessionRepository<? extends Session> repository = new ReactiveRedisSessionRepository(redisTemplate);

ReactiveRedisConnectionFactory の作成方法の詳細については、「Spring Data Redis リファレンス」を参照してください。

9.8.2. @EnableRedisWebSession を使用する

Web 環境では、新しい ReactiveRedisSessionRepository を作成する最も簡単な方法は、@EnableRedisWebSession を使用することです。次の属性を使用して、構成をカスタマイズできます。

  • maxInactiveIntervalInSeconds: セッションが期限切れになるまでの時間(秒単位)

  • redisNamespace: セッションのアプリケーション固有の名前空間を構成できます。Redis キーとチャネル ID は、<redisNamespace>: の q プレフィックスで始まります。

  • flushMode: Redis にデータを書き込むタイミングを指定できます。デフォルトは、save が ReactiveSessionRepository で呼び出された場合のみです。FlushMode.IMMEDIATE の値は、できるだけ早く Redis に書き込みます。

最適化された書き込み

ReactiveRedisSessionRepository によって管理される Session インスタンスは、変更されたプロパティを追跡し、それらのみを更新します。つまり、属性が 1 回書き込まれ、何度も読み取られる場合、その属性を 1 回だけ書き込む必要があります。

9.8.3. Redis でのセッションの表示

redis-cli をインストールした (英語) 後、redis-cli (英語) を使用して Redis (英語) の値を調べることができます。例:ターミナルウィンドウに次のコマンドを入力できます。

$ redis-cli
redis 127.0.0.1:6379> keys *
1) "spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021" (1)
1 このキーのサフィックスは、Spring Session のセッション ID です。

hkeys コマンドを使用して、各セッションの属性を表示することもできます。次の例は、その方法を示しています。

redis 127.0.0.1:6379> hkeys spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021
1) "lastAccessedTime"
2) "creationTime"
3) "maxInactiveInterval"
4) "sessionAttr:username"
redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021 sessionAttr:username
"\xac\xed\x00\x05t\x00\x03rob"

9.9. MapSessionRepository を使用する

MapSessionRepository を使用すると、Session を Map に永続化できます。キーは、Session ID であり、値は Session です。ConcurrentHashMap を使用した実装は、テストまたは便利なメカニズムとして使用できます。または、分散 Map 実装で使用することもできます。例:Hazelcast で使用できます。

9.9.1. MapSessionRepository のインスタンス化

次の例は、新しいインスタンスを作成する方法を示しています。

SessionRepository<? extends Session> repository = new MapSessionRepository(new ConcurrentHashMap<>());

9.9.2. Spring Session と Hazlecast の使用

ヘーゼルキャストサンプルは、Hazelcast で Spring Session を使用する方法を示す完全なアプリケーションです。

実行するには、次のコマンドを使用します。

	./gradlew :samples:hazelcast:tomcatRun

HazelcastSpring サンプルは、Hazelcast および Spring Security で Spring Session を使用する方法を示す完全なアプリケーションです。

これには、SessionCreatedEventSessionDeletedEvent および SessionExpiredEvent の起動をサポートする Hazelcast MapListener 実装の例が含まれています。

実行するには、次のコマンドを使用します。

	./gradlew :samples:hazelcast-spring:tomcatRun

9.10. ReactiveMapSessionRepository を使用する

ReactiveMapSessionRepository を使用すると、Session を Map に永続化できます。キーは、Session ID であり、値は Session です。ConcurrentHashMap を使用した実装は、テストまたは便利なメカニズムとして使用できます。または、提供された Map がノンブロッキングである必要があるという要件で、分散 Map 実装で使用することもできます。

9.11. JdbcIndexedSessionRepository を使用する

JdbcIndexedSessionRepository は、Spring の JdbcOperations を使用してセッションをリレーショナルデータベースに格納する SessionRepository 実装です。Web 環境では、これは通常 SessionRepositoryFilter と組み合わせて使用されます。この実装は、セッションイベントの公開をサポートしていないことに注意してください。

9.11.1. JdbcIndexedSessionRepository のインスタンス化

次の例は、新しいインスタンスを作成する方法を示しています。

JdbcTemplate jdbcTemplate = new JdbcTemplate();

// ... configure jdbcTemplate ...

TransactionTemplate transactionTemplate = new TransactionTemplate();

// ... configure transactionTemplate ...

SessionRepository<? extends Session> repository = new JdbcIndexedSessionRepository(jdbcTemplate,
		transactionTemplate);

JdbcTemplate および PlatformTransactionManager を作成および構成する方法の詳細については、Spring Framework リファレンスドキュメントを参照してください。

9.11.2. @EnableJdbcHttpSession を使用する

Web 環境では、新しい JdbcIndexedSessionRepository を作成する最も簡単な方法は、@EnableJdbcHttpSession を使用することです。完全な使用例はサンプルとガイド (ここから開始) にあります。次の属性を使用して構成をカスタマイズできます。

  • tableName: Spring Session がセッションを格納するために使用するデータベーステーブルの名前

  • maxInactiveIntervalInSeconds: セッションが期限切れになるまでの時間(秒単位)

LobHandler のカスタマイズ

LobHandler を実装する springSessionLobHandler という名前の Bean を作成することにより、BLOB 処理をカスタマイズできます。

ConversionService のカスタマイズ

ConversionService インスタンスを提供することにより、セッションのデフォルトの直列化と逆直列化をカスタマイズできます。通常の Spring 環境で作業する場合、デフォルトの ConversionService Bean(conversionService という名前)が自動的に取得され、直列化と逆直列化に使用されます。ただし、springSessionConversionService という名前の Bean を提供することにより、デフォルトの ConversionService をオーバーライドできます。

9.11.3. ストレージの詳細

デフォルトでは、この実装は SPRING_SESSION テーブルと SPRING_SESSION_ATTRIBUTES テーブルを使用してセッションを格納します。すでに説明したように、テーブル名をカスタマイズできることに注意してください。その場合、属性の格納に使用されるテーブルには、_ATTRIBUTES という接尾辞が付いた提供されたテーブル名を使用して名前が付けられます。さらにカスタマイズが必要な場合は、set*Query setter メソッドを使用して、リポジトリによって使用される SQL クエリをカスタマイズできます。この場合、sessionRepository Bean を手動で構成する必要があります。

さまざまなデータベースベンダー間の違いのため、特にバイナリデータの保存に関しては、データベースに固有の SQL スクリプトを使用してください。ほとんどの主要なデータベースベンダーのスクリプトは、org/springframework/session/jdbc/schema-*.sql としてパッケージ化されています。ここで、* はターゲットデータベースタイプです。

例:PostgreSQL では、次のスキーマスクリプトを使用できます。

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)
);

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 BYTEA 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
);

MySQL データベースでは、次のスクリプトを使用できます。

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)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

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
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;

9.11.4. トランザクション管理

JdbcIndexedSessionRepository のすべての JDBC 操作は、トランザクション方式で実行されます。トランザクションは、既存のトランザクションとの干渉による予期しない動作を回避するために、伝播を REQUIRES_NEW に設定して実行されます(たとえば、すでに読み取り専用トランザクションに参加しているスレッドで save 操作を実行する)。

9.12. HazelcastIndexedSessionRepository を使用する

HazelcastIndexedSessionRepository は、Hazelcast の分散 IMap にセッションを格納する SessionRepository 実装です。Web 環境では、これは通常 SessionRepositoryFilter と組み合わせて使用されます。

9.12.1. HazelcastIndexedSessionRepository のインスタンス化

次の例は、新しいインスタンスを作成する方法を示しています。

Config config = new Config();

// ... configure Hazelcast ...

HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(config);

HazelcastIndexedSessionRepository repository = new HazelcastIndexedSessionRepository(hazelcastInstance);

Hazelcast インスタンスを作成および構成する方法の詳細については、Hazelcast のドキュメント (英語) を参照してください。

9.12.2. @EnableHazelcastHttpSession を使用する

Hazelcast (英語) を SessionRepository のバッキングソースとして使用するには、@EnableHazelcastHttpSession アノテーションを @Configuration クラスに追加します。そうすることで、@EnableSpringHttpSession アノテーションによって提供される機能が拡張されますが、Hazelcast で SessionRepository が使用できるようになります。構成を機能させるには、単一の HazelcastInstance Bean を提供する必要があります。完全な構成例はサンプルとガイド (ここから開始) にあります。

9.12.3. 基本的なカスタマイズ

@EnableHazelcastHttpSession で次の属性を使用して、構成をカスタマイズできます。

  • maxInactiveIntervalInSeconds: セッションが期限切れになるまでの時間(秒単位)。デフォルトは 1800 秒です (30 分)

  • sessionMapName: セッションデータを格納するために Hazelcast で使用される分散 Map の名前。

9.12.4. セッションイベント

MapListener を使用して、分散 Map から追加、削除、削除されたエントリに応答すると、これらのイベントにより、ApplicationEventPublisher を介した SessionCreatedEventSessionExpiredEvent および SessionDeletedEvent イベントの公開がトリガーされます。

9.12.5. ストレージの詳細

セッションは、Hazelcast の分散 IMap に保存されます。IMap インターフェースメソッドは、get() および put() セッションに使用されます。さらに、values() メソッドは、適切な ValueExtractor (Hazelcast に登録する必要があります)とともに、FindByIndexNameSessionRepository#findByIndexNameAndIndexValue 操作をサポートします。この構成の詳細については、HazelcastSpring サンプルを参照してください。IMap でのセッションの有効期限は、put() から IMap へのエントリの存続時間を設定するための Hazelcast のサポートによって処理されます。存続時間より長くアイドル状態になっているエントリ(セッション)は、IMap から自動的に削除されます。

Hazelcast 構成内の IMap に対して、max-idle-seconds や time-to-live-seconds などの設定を構成する必要はありません。

Hazelcast の MapStore を使用してセッション IMap を永続化する場合、MapStore からセッションをリロードするときに次の制限が適用されることに注意してください。

  • リロードにより EntryAddedListener がトリガーされ、SessionCreatedEvent が再公開されます

  • 再ロードでは、特定の IMap にデフォルトの TTL が使用されるため、セッションは元の TTL を失います。

9.13. CookieSerializer を使用する

CookieSerializer は、セッション Cookie の書き込み方法を定義するロールを果たします。Spring Session には、DefaultCookieSerializer を使用したデフォルトの実装が付属しています。

9.13.1. CookieSerializer を Bean として公開する

CookieSerializer を Spring として公開する Bean は、@EnableRedisHttpSession のような構成を使用する場合、既存の構成を拡張します。

次の例は、その方法を示しています。

	@Bean
	public CookieSerializer cookieSerializer() {
		DefaultCookieSerializer serializer = new DefaultCookieSerializer();
		serializer.setCookieName("JSESSIONID"); (1)
		serializer.setCookiePath("/"); (2)
		serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$"); (3)
		return serializer;
	}
1Cookie の名前を JSESSIONID にカスタマイズします。
2Cookie のパスを(コンテキストルートのデフォルトではなく) / になるようにカスタマイズします。
3 ドメイン名のパターン(正規表現)を ^.?\\.(\\w\\.[a-z]+)$ にカスタマイズします。これにより、ドメインやアプリケーション間でセッションを共有できます。正規表現が一致しない場合、ドメインは設定されず、既存のドメインが使用されます。正規表現が一致する場合、最初のグループ化: Oracle (英語) がドメインとして使用されます。これは、https://child.example.com (英語) へのリクエストがドメインを example.com に設定することを意味します。ただし、http://localhost:8080/ または https://192.168.1.100:8080/ (英語) へのリクエストでは、Cookie が未設定のままであるため、本番環境で変更を加えることなく、開発中も機能します。
ドメイン名はレスポンスに反映されるため、有効なドメイン文字のみを照合する必要があります。そうすることで、悪意のあるユーザーが HTTP レスポンスの分割 (英語) などの攻撃を実行するのを防ぎます。

9.13.2. CookieSerializer のカスタマイズ

DefaultCookieSerializer で次の構成オプションのいずれかを使用して、セッション Cookie の書き込み方法をカスタマイズできます。

  • cookieName: 使用する Cookie の名前。デフォルト: SESSION.

  • useSecureCookie: 安全な Cookie を使用するかどうかを指定します。デフォルト: 作成時の HttpServletRequest.isSecure() の値を使用します。

  • cookiePath: クッキーのパス。デフォルト: コンテキストルート。

  • cookieMaxAge: セッションの作成時に設定される Cookie の最大有効期間を指定します。デフォルト: -1 は、ブラウザーを閉じたときに Cookie を削除する必要があることを示します。

  • jvmRoute: セッション ID に追加され、Cookie に含まれるサフィックスを指定します。セッションアフィニティのためにルーティングする JVM を識別するために使用されます。一部の実装(つまり、Redis)では、このオプションはパフォーマンス上の利点を提供しません。ただし、特定のユーザーのログを追跡できます。

  • domainName: Cookie に使用する特定のドメイン名を指定できます。このオプションは理解しやすいですが、多くの場合、開発環境と本番環境の間で異なる構成が必要になります。代わりに domainNamePattern を参照してください。

  • domainNamePatternHttpServletRequest#getServerName() からドメイン名を抽出するために使用される大文字と小文字を区別しないパターン。パターンは、Cookie ドメインの値を抽出するために使用される単一のグループ化を提供する必要があります。正規表現が一致しない場合、ドメインは設定されず、既存のドメインが使用されます。正規表現が一致する場合、最初のグループ化: Oracle (英語) がドメインとして使用されます。

  • sameSiteSameSite cookie ディレクティブの値。SameSite cookie ディレクティブの直列化を無効にするには、この値を null に設定します。デフォルト: Lax

ドメイン名はレスポンスに反映されるため、有効なドメイン文字のみを照合する必要があります。そうすることで、悪意のあるユーザーが HTTP レスポンスの分割 (英語) などの攻撃を実行するのを防ぎます。

10. SessionRepository のカスタマイズ

カスタム SessionRepositoryAPI の実装は、かなり簡単な作業です。カスタム実装を @EnableSpringHttpSession サポートと組み合わせると、既存の Spring Session 構成機能とインフラストラクチャを再利用できます。ただし、さらに検討する価値のある側面がいくつかあります。

HTTP リクエストのライフサイクル中、HttpSession は通常 SessionRepository に 2 回永続化されます。最初の永続化操作は、クライアントがセッション ID にアクセスできるようになるとすぐにセッションが使用可能になるようにすることです。また、セッションにさらに変更が加えられる可能性があるため、セッションがコミットされた後に書き込む必要があります。これを念頭に置いて、通常、SessionRepository 実装は変更を追跡して、デルタのみが保存されるようにすることをお勧めします。これは、複数のリクエストが同じ HttpSession で動作するため、競合状態が発生し、リクエストがセッション属性への相互の変更を上書きする、高度に並行した環境で特に重要です。Spring Session によって提供されるすべての SessionRepository 実装は、説明されているアプローチを使用してセッションの変更を永続化し、カスタム SessionRepository を実装する際のガイダンスとして使用できます。

カスタム ReactiveSessionRepository の実装にも同じ推奨事項が適用されることに注意してください。この場合、@EnableSpringWebSession を使用する必要があります。

11. 2.x へのアップグレード

新しいメジャーリリースバージョンでは、Spring Session チームはいくつかの非パッシブな変更を行う機会を得ました。これらの変更の焦点は、Spring Session の API を改善および調和し、非推奨のコンポーネントを削除することです。

11.1. ベースラインの更新

Spring Session 2.0 は、コードベース全体が Java 8 ソースコードに基づいているため、ベースラインとして Java 8 と Spring Framework 5.0 が必要です。Spring Framework のアップグレードの詳細については、Spring Framework 5.x へのアップグレード: GitHub (英語) を参照してください。

11.2. 交換および削除されたモジュール

プロジェクトによるモジュールの分割の一環として、既存の spring-session が spring-session-core モジュールに置き換えられました。spring-session-core モジュールは、API とコンポーネントの共通セットのみを保持しますが、他のモジュールには、適切な SessionRepository の実装とそのデータストアに関連する機能が含まれています。これは、以前は単純な依存関係アグリゲーターヘルパーモジュールであったいくつかの既存のモジュールに適用されます。新しいモジュール配置では、次のモジュールが実際に実装を実行します。

  • Spring Session Data Redis

  • Spring Session JDBC

  • Spring Session Hazelcast

また、次のモジュールがメインプロジェクトリポジトリから削除されます。

  • Spring Session データ MongoDB

  • Spring Session データ GemFire

これら 2 つは別々のリポジトリに移動し、新しいアーティファクト名で引き続き利用できることに注意してください。

11.3. 置換および削除されたパッケージ、クラス、メソッド

パッケージ、クラス、メソッドに次の変更が加えられました。

  • ExpiringSession API は Session API に統合されました。

  • Session API は、Java 8 を最大限に活用するように拡張されました。

  • Session API は、changeSessionId サポートで拡張されました。

  • SessionRepository API が更新され、Spring Data メソッドの命名規則との整合性が向上しました。

  • AbstractSessionEvent とそのサブクラスは、基礎となる Session オブジェクトなしでは構築できなくなりました。

  • RedisOperationsSessionRepository で使用される Redis 名前空間は、部分的に構成可能ではなく、完全に構成可能になりました。

  • Redis 構成のサポートが更新され、Spring セッション固有の RedisTemplate Bean の登録が回避されました。

  • JDBC 構成のサポートが更新され、Spring セッション固有の JdbcTemplate Bean の登録を回避しました。

  • 以前に非推奨になったクラスとメソッドは、コードベース全体で削除されました

11.4. サポートの終了

HttpSessionStrategy への変更と、リアクティブワールドからの対応するものへの調整の一環として、単一のブラウザーインスタンスで複数のユーザーのセッションを管理するためのサポートが削除されました。この機能を置き換える新しい API の導入は、将来のリリースで検討されています。

12. Spring Session コミュニティ

あなたを私たちのコミュニティの一員と見なしてうれしいです。次のセクションでは、Spring Session コミュニティと対話する方法についてさらに説明します。

12.1. サポート

spring-session タグを使用したスタックオーバーフロー (英語) で質問することで助けを得ることができます。同様に、StackOverflow に関する質問に答えて他の人を手助けすることをお勧めします。

12.2. ソースコード

ソースコードは GitHub の https://github.com/spring-projects/spring-session/ (英語) にあります

12.3. 課題追跡

12.4. コントリビュートする

12.5. ライセンス

Spring Session は、Apache 2.0 ライセンス (英語) でリリースされたオープンソースソフトウェアです。

12.6. コミュニティ拡張

名前 ロケーション

Spring Session OrientDB

https://github.com/maseev/spring-session-orientdb (英語)

Spring Session インフィニスパン

https://infinispan.org/docs/dev/user_guide/user_guide.html#externalizing_session_using_spring_session (英語)

13. 最小要件

Spring Session の最小要件は次のとおりです。

  • Java 8+.

  • サーブレットコンテナー(必須ではありません)で実行する場合、Servlet 3.1+.

  • 他の Spring ライブラリ(必須ではありません)を使用する場合、最低限必要なバージョンは Spring 5.0.x. です。

  • @EnableRedisHttpSession には Redis 2.8+. が必要ですこれはセッションの有効期限をサポートするために必要です

  • @EnableHazelcastHttpSession には Hazelcast3.6 + が必要です。これは FindByIndexNameSessionRepository をサポートするために必要です

基本的に、Spring Session は spring-jcl にのみ依存する必要があります。他の Spring 依存関係なしで Spring Session を使用する例については、hazelcast サンプルアプリケーションを参照してください。