HttpSession 統合

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

なぜ Spring Session と HttpSession

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

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

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

Redis を使用した HttpSession 

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

Redis Java ベースの構成

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

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

Spring Java 構成

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

@Configuration(proxyBeanMethods = false)
@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 を確実にロードするためのメカニズムも提供します。

Redis XML ベースの構成

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

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

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 が呼び出されます。

JDBC を使用した HttpSession 

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

JDBCJava ベースの構成

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

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

Spring Java 構成

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

@Configuration(proxyBeanMethods = false)
@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 を確実にロードするためのメカニズムも提供します。

複数の DataSources

Spring Session は @SpringSessionDataSource 修飾子を提供し、どの DataSource Bean を JdbcIndexedSessionRepository に注入するかを明示的に宣言できるようにします。これは、アプリケーションコンテキストに複数の DataSource Bean が存在するシナリオで特に役立ちます。

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

Config.java
@EnableJdbcHttpSession
public class Config {

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

	@Bean
	public HikariDataSource secondDataSource() {
		// ...
	}
}
1 この修飾子は、firstDataSource が Spring Session によって使用されることを宣言します。

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 が呼び出されます。

JDBC SpringBoot ベースの構成

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

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

Spring Boot の設定

必要な依存関係を追加した後、Spring Boot 構成を作成できます。ファーストクラスの自動構成サポートのおかげで、依存関係を追加するだけで、Spring Boot がリレーショナルデータベースに基づいた Spring Session をセットアップします。

単一の Spring Session モジュールがクラスパスに存在する場合、Spring Boot はそのストア実装を自動的に使用します。複数の実装がある場合は、上記のように、セッションの保存に使用する StoreType を選択する必要があります。

内部的には、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/schema-@@platform@@.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 がこれらの両方の手順を実行してくれます。

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 と相互作用するものの前に配置することが重要である理由を浮き彫りにします。

HttpSession および RESTful API

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

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

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 ヘッダーを使用して現在のセッション情報を伝達します。

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

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 を継承することです。

HttpSessionListener を使用する

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

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

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

  • すべての HttpSessionListener を SessionEventHttpSessionListenerAdapter に注入します

enableIndexingAndEvents を true@EnableRedisHttpSession(enableIndexingAndEvents = true) に設定して Redis サポートを使用する場合は、すべての 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"/>