# HttpSession积分

Spring Session 提供了与HttpSession的透明集成。这意味着开发人员可以使用 Spring Session 支持的实现来切换HttpSession实现。

# 为什么 Spring session 和HttpSession

我们已经提到, Spring Session 提供了与HttpSession的透明集成,但是我们从中得到了什么好处呢?

  • 群集会话: Spring Session 使得在不绑定到特定于应用程序容器的解决方案的情况下支持群集会话变得非常简单。

  • RESTful API: Spring session 让在 header 中提供会话 ID 可以与RESTful API一起工作

# HttpSessionwith redis

使用 Spring session withHttpSession是通过在使用HttpSession之前添加一个 Servlet 过滤器来实现的。你可以通过以下两种方式选择启用此功能:

# Redis 基于 Java 的配置

这一节描述了如何使用基于 Java 的配置使用 Redis 来支持HttpSession

HttpSession 示例提供了如何使用 Java 配置集成 Spring Session 和HttpSession的工作示例,
你可以在接下来的几节中阅读集成的基本步骤,但是,我们鼓励你在与自己的应用程序集成时遵循详细的 HttpSession 指南。

# Spring Java 配置

在添加了所需的依赖关系之后,我们就可以创建我们的 Spring 配置了。 Spring 配置负责创建一个 Servlet 过滤器,该过滤器将HttpSession实现替换为由 Spring Session 支持的实现。为此,添加以下 Spring 配置:

@EnableRedisHttpSession (1)
public class Config {

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

}
1 @EnableRedisHttpSession注释创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了Filter
过滤器负责替换要由 Spring Session 支持的HttpSession实现。
在此实例中, Spring Session 由 Redis 支持。
2 我们创建一个RedisConnectionFactory将 Spring Session 连接到 Redis 服务器。
我们将连接配置为在默认端口(6379)上连接到 localhost。
有关配置 Spring 数据 Redis 的更多信息,请参见参考文献 (opens new window)

# Java Servlet 容器初始化

我们的Spring Configuration创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了FilterspringSessionRepositoryFilter Bean 负责用 Spring Session 支持的自定义实现替换HttpSession

为了让我们的Filter发挥其魔力, Spring 需要加载我们的Config类。最后,我们需要确保我们的 Servlet 容器(即 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
这样做可以确保 Spring Bean 以springSessionRepositoryFilter的名称在我们的 Servlet 容器中为每个请求注册。
2 AbstractHttpSessionApplicationInitializer还提供了一种机制,以确保 Spring 加载我们的Config

# 基于 XML 的 Redis 配置

本节介绍如何使用基于 XML 的配置使用 Redis 来支持HttpSession

HttpSession XML 示例提供了如何使用 XML 配置集成 Spring Session 和HttpSession的工作示例,
你可以在接下来的几个部分中阅读集成的基本步骤,但是,我们鼓励你在与自己的应用程序集成时遵循详细的 HttpSession XML 指南。

# Spring xml 配置

在添加了所需的依赖关系之后,我们就可以创建我们的 Spring 配置了。 Spring 配置负责创建一个 Servlet 过滤器,该过滤器将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"/>
1 我们使用<context:annotation-config/>RedisHttpSessionConfiguration的组合,因为 Spring Session 尚未提供 XML 名称空间支持(参见gh-104 (opens new window))。
这将创建一个名称为springSessionRepositoryFilter的 Spring Bean 实现Filter
过滤器负责替换要由 Spring Session 支持的HttpSession实现。
在此实例中, Spring Session 由 Redis 支持。
2 我们创建一个RedisConnectionFactory将 Spring Session 连接到 Redis 服务器。
我们将连接配置为在默认端口(6379)
上连接到 localhost。有关配置 Spring 数据 Redis 的更多信息,请参见参考文献 (opens new window)

# xml Servlet 容器初始化

我们的Spring Configuration创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了FilterspringSessionRepositoryFilter Bean 负责用 Spring Session 支持的自定义实现替换HttpSession

为了使我们的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](https://DOCS. Spring.io/ Spring/DOCS/5.3.16/ Spring-framework-reference/core.html#context-create)读取 contextconfiglocation 并获取 session.xml 配置。

最后,我们需要确保我们的 Servlet 容器(即 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](https://DOCS. Spring.io/ Spring-framework/DOCS/5.3.16/javadoc-api/org/springframework/web/filter/delegatingfilterproxy.html)以springSessionRepositoryFilter的名称查找 Bean 并将其强制转换为Filter。对于每一个调用DelegatingFilterProxy的请求,都会调用springSessionRepositoryFilter

# HttpSession with Mongo

使用 Spring 与HttpSession会话是通过在使用HttpSession的任何之前添加一个 Servlet 过滤器来实现的。

本节介绍如何使用基于 Java 的配置使用 Mongo 返回HttpSession

HttpSession Mongo 示例提供了一个工作示例,说明如何使用 Java 配置集成 Spring Session 和HttpSession
你可以阅读下面的集成基本步骤,但鼓励你在与自己的应用程序集成时遵循详细的 HttpSession 指南。

你所要做的就是添加以下 Spring 配置:

@EnableMongoHttpSession (1)
public class HttpSessionConfig {

	@Bean
	public JdkMongoSessionConverter jdkMongoSessionConverter() {
		return new JdkMongoSessionConverter(Duration.ofMinutes(30)); (2)
	}

}
1 @EnableMongoHttpSession注释创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了 filter。
这个过滤器用 MongoDB 支持的 Bean 替换了默认的HttpSession
2 将会话超时时间配置为 30 分钟。

# 会话序列化机制

为了能够在 MongoDB 中持久化会话对象,我们需要提供序列化/反序列化机制。

默认情况下, Spring Session MongoDB 将使用JdkMongoSessionConverter

但是,只需在启动应用程序中添加以下代码,就可以切换到JacksonMongoSessionConverter:

@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
    return new JacksonMongoSessionConverter();
}
# JacksonMongosessionConverter

这种机制使用 Jackson 序列化到/来自 JSON 的会话对象。

通过创建以下内容 Bean:

@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
    return new JacksonMongoSessionConverter();
}

…你可以从默认的(基于 JDK 的序列化)切换到使用 Jackson。

如果你正在与 Spring Security 集成(通过将你的会话存储在 MongoDB 中),则该配置将
注册适当的白名单组件,以便 Spring Security 能够正常工作。

如果你想提供自定义的 Jackson 模块,你可以通过显式地注册如下所示的模块来实现这一点:

@Configuration
@EnableMongoHttpSession
static class Config extends BaseConfig {

	@Bean
	AbstractMongoSessionConverter mongoSessionConverter() {
		return new JacksonMongoSessionConverter(Collections.singletonList(new GeoModule()));
	}

}
# JDKMongosessionConverter

JdkMongoSessionConverter使用标准的 Java 序列化来持久化以二进制形式映射到 MongoDB 的会话属性。但是,诸如 ID、访问时间等标准会话元素仍然被写成一个普通的 Mongo 对象,并且可以在不需要额外的努力的情况下进行读取和查询。如果没有明确的JdkMongoSessionConverter Bean 定义,则使用AbstractMongoSessionConverter

还有一个构造函数接受SerializerDeserializer对象,允许你传递自定义的实现,这在你想要使用非默认的类加载器时尤其重要。

# HttpSessionwith JDBC

通过在使用HttpSession的任何内容之前添加一个 Servlet 过滤器,可以使用与HttpSession的 Spring Session 。你可以选择以下任何一种方式:

# 基于 Java 的 JDBC 配置

本节描述了在使用基于 Java 的配置时如何使用关系数据库来备份HttpSession

HttpSession JDBC 示例提供了如何通过使用 Java 配置来集成 Spring Session 和HttpSession的工作示例,
你可以在接下来的几个部分中阅读集成的基本步骤,但我们鼓励你在与自己的应用程序集成时遵循详细的 HttpSession JDBC 指南。

# Spring Java 配置

在添加了所需的依赖关系之后,我们就可以创建我们的 Spring 配置了。 Spring 配置负责创建一个 Servlet 过滤器,该过滤器用 Spring Session 支持的实现替换HttpSession实现。为此,添加以下 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 是由关系数据库支持的。
2 我们创建了一个dataSource,它将 Spring Session 连接到 H2 数据库的嵌入式实例。
我们通过使用 Spring Session 中包含的 SQL 脚本来配置 H2 数据库来创建数据库表。
3 我们创建一个transactionManager,它管理先前配置的dataSource的事务。

有关如何配置与数据访问相关的问题的更多信息,请参见Spring Framework Reference Documentation (opens new window)

# Java Servlet 容器初始化

我们的Spring Configuration创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了FilterspringSessionRepositoryFilter Bean 负责用 Spring Session 支持的自定义实现替换HttpSession

为了让我们的Filter发挥其魔力, Spring 需要加载我们的Config类。最后,我们需要确保我们的 Servlet 容器(即 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 在我们的 Servlet 容器中为每个请求注册。
2 AbstractHttpSessionApplicationInitializer还提供了一种机制,以确保 Spring 加载我们的Config

# 多个数据源

Spring Session 提供了@SpringSessionDataSource限定符,允许你显式地声明应该在JdbcIndexedSessionRepository中注入哪个DataSource Bean。这在应用程序上下文中存在多个DataSourcebean 的场景中特别有用。

下面的示例展示了如何做到这一点:

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 此限定符声明 Spring Session 将使用 FirstDataSource。

# 基于 XML 的 JDBC 配置

本节描述了在使用基于 XML 的配置时如何使用关系数据库来备份HttpSession

HttpSession JDBC XML 示例提供了如何通过使用 XML 配置来集成 Spring Session 和HttpSession的工作示例,
你可以在接下来的几个部分中阅读集成的基本步骤,但是,我们鼓励你在与自己的应用程序集成时遵循详细的 HttpSession JDBC XML 指南。

# Spring xml 配置

在添加了所需的依赖关系之后,我们可以创建我们的 Spring 配置。 Spring 配置负责创建一个 Servlet 过滤器,该过滤器用 Spring Session 支持的实现替换HttpSession实现。下面的清单显示了如何添加以下 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>
1 我们使用<context:annotation-config/>的组合和JdbcHttpSessionConfiguration因为 Spring session 尚未提供 XML 名称空间支持(参见gh-104 (opens new window))。
这将创建一个名为springSessionRepositoryFilter的 Spring Bean。
Bean 实现Filter
过滤器负责替换要由 Spring session 支持的HttpSession实现。
在此实例中, Spring Session 由关系数据库支持。
2 我们创建一个dataSource,它将 Spring Session 连接到 H2 数据库的嵌入式实例。
我们通过使用 Spring Session 中包含的 SQL 脚本配置 H2 数据库来创建数据库表。
3 我们创建一个transactionManager,它管理先前配置的dataSource的事务。

有关如何配置与数据访问相关的问题的更多信息,请参见Spring Framework Reference Documentation (opens new window)

# xml Servlet 容器初始化

我们的Spring Configuration创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了FilterspringSessionRepositoryFilter Bean 负责用 Spring Session 支持的自定义实现替换HttpSession

为了使我们的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](https://DOCS. Spring.io/ Spring/DOCS/5.3.16/ Spring-framework-reference/core.html#context-create)读取contextConfigLocation并获取 session.xml 配置。

最后,我们需要确保我们的 Servlet 容器(即 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](https://DOCS. Spring.io/ Spring-framework/DOCS/5.3.16/javadoc-api/org/springframework/web/filter/delegatingfilterproxy.html)查找一个名为springSessionRepositoryFilter的 Bean 并将其强制转换为Filter。对于每个调用DelegatingFilterProxy的请求,都调用springSessionRepositoryFilter

# JDBC Spring 基于引导的配置

本节描述了在使用 Spring 引导时如何使用关系数据库来备份HttpSession

HttpSession JDBC Spring Boot Sample提供了如何使用 Spring boot 集成 Spring Session 和HttpSession的工作示例,
你可以在接下来的几个部分中阅读集成的基本步骤,但是,我们鼓励你在与自己的应用程序集成时遵循详细的 HttpSession JDBC Spring 引导指南。

# Spring 引导配置

在添加了所需的依赖项之后,我们可以创建我们的 Spring 引导配置。多亏了一流的自动配置支持,在关系数据库支持下设置 Spring Session 就像向application.properties添加一个配置属性一样简单。下面的清单展示了如何做到这一点:

SRC/主/资源/应用程序.properties

spring.session.store-type=jdbc # Session store type.

如果在 Classpath 上存在单个 Spring Session 模块,则 Spring 引导自动使用该存储实现。如果有多个实现,则必须选择要用来存储会话的 StoreType,如上面所示。

Spring Boot 应用的配置相当于手动添加@EnableJdbcHttpSession注释。这将创建一个名为springSessionRepositoryFilter的 Spring Bean。 Bean 实现Filter。过滤器负责替换要由 Spring Session 支持的HttpSession实现。

你可以使用application.properties来进一步自定义。下面的清单展示了如何做到这一点:

SRC/主/资源/应用程序.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 引导文档的Spring Session (opens new window)部分。

# 配置DataSource

Spring 启动会自动创建DataSource,该会话将 Spring Session 连接到 H2 数据库的嵌入式实例。在生产环境中,你需要更新配置以指向关系数据库。例如,你可以在应用程序中包含以下内容:

SRC/主/资源/应用程序.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 引导文档的配置数据源 (opens new window)部分。

# Servlet 容器初始化

我们的Spring Boot Configuration创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了FilterspringSessionRepositoryFilter Bean 负责用 Spring Session 支持的自定义实现替换HttpSession

为了让我们的Filter发挥其魔力, Spring 需要加载我们的Config类。最后,我们需要确保我们的 Servlet 容器(即 Tomcat)为每个请求使用我们的springSessionRepositoryFilter。幸运的是,Boot 为我们解决了这两个步骤。

# HttpSession with Hazelcast

使用 Spring 与HttpSession会话是通过在任何使用HttpSession的之前添加一个 Servlet 过滤器来实现的。

本节介绍如何使用基于 Java 的配置使用 HazelCast 来支持HttpSession

Hazelcast Spring Sample提供了如何通过使用 Java 配置来集成 Spring Session 和HttpSession的工作示例,
你可以在接下来的几个部分中阅读集成的基本步骤,但是,我们鼓励你在与自己的应用程序集成时遵循详细的 Hazelcast Spring 指南。

# Spring 配置

在添加了所需的依赖关系之后,我们可以创建我们的 Spring 配置。 Spring 配置负责创建 Servlet 过滤器,该过滤器用 Spring Session 支持的实现替换HttpSession实现。为此,添加以下 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));
		SerializerConfig serializerConfig = new SerializerConfig();
		serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class);
		config.getSerializationConfig().addSerializerConfig(serializerConfig); (3)
		return Hazelcast.newHazelcastInstance(config); (4)
	}

}
1 @EnableHazelcastHttpSession注释创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了Filter
过滤器负责替换要由 Spring Session 支持的HttpSession实现。
在此实例中, Spring Session 由 Hazelcast 支持。
2 为了支持通过主名索引检索会话,需要注册一个适当的ValueExtractor
Spring Session 为此提供了PrincipalNameExtractor
3 为了有效地序列化MapSession对象,需要注册HazelcastSessionSerializer。如果未设置
,HazelCast 将使用本机 Java 序列化来序列化会话。
4 我们创建一个HazelcastInstance将 Spring Session 连接到 Hazelcast。
默认情况下,应用程序启动并连接到 Hazelcast 的嵌入式实例。
有关配置 Hazelcast 的更多信息,请参见参考文献 (opens new window)
如果HazelcastSessionSerializer是首选的,则需要在所有 Hazelcast 集群成员启动之前对其进行配置。
在 Hazelcast 集群中,所有成员都应该对会话使用相同的序列化方法。此外,如果使用了 HazelCast 客户机/服务器拓扑
,那么成员和客户机都必须使用相同的序列化方法。序列化器可以通过ClientConfigSerializerConfiguration相同的成员来注册。

# Servlet 容器初始化

我们的Spring Configuration创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了FilterspringSessionRepositoryFilter Bean 负责用 Spring Session 支持的自定义实现替换HttpSession

为了让我们的Filter发挥其魔力, Spring 需要加载我们的SessionConfig类。由于我们的应用程序已经通过使用SecurityInitializer类加载了 Spring 配置,因此我们可以将SessionConfig类添加到其中。下面的清单展示了如何做到这一点:

SRC/main/java/sample/securityinitializer.java

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {

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

}

最后,我们需要确保我们的 Servlet 容器(即 Tomcat)为每个请求使用我们的springSessionRepositoryFilter。在 Spring security 的springSecurityFilterChain之前调用 Spring session 的springSessionRepositoryFilter是极其重要的。这样做可以确保 Spring 安全性使用的HttpSession得到 Spring Session 的支持。幸运的是, Spring Session 提供了一个名为AbstractHttpSessionApplicationInitializer的实用程序类,这使得这样做很容易。下面的示例展示了如何做到这一点:

SRC/main/java/sample/initializer.java

public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
我们类的名称(Initializer)并不重要。重要的是,我们扩展AbstractHttpSessionApplicationInitializer

通过扩展AbstractHttpSessionApplicationInitializer,我们确保在 Spring Security 的springSecurityFilterChain之前的每个请求都将名为springSessionRepositoryFilter的 Spring Bean 注册到我们的 Servlet 容器中。

# 集成如何工作

幸运的是,HttpSessionHttpServletRequest(获取HttpSession的 API)都是接口。这意味着我们可以为这些 API 中的每一个提供我们自己的实现。

本节描述 Spring Session 如何提供与HttpSession的透明集成。我们提供这些内容,这样你就可以了解幕后发生了什么。这个功能已经集成了,你不需要自己实现这个逻辑。

首先,我们创建一个自定义的HttpServletRequest,它返回一个HttpSession的自定义实现。它看起来是这样的:

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的 Servlet 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 应用程序中使用 Spring Session 来支持使用头部进行身份验证,
你可以遵循下面几节中描述的集成的基本步骤,但是,我们鼓励你在与自己的应用程序集成时遵循详细的 REST 指南。

# Spring 配置

在添加了所需的依赖关系之后,我们可以创建我们的 Spring 配置。 Spring 配置负责创建一个 Servlet 过滤器,该过滤器将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注释创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了Filter
过滤器负责替换要由 Spring Session 支持的HttpSession实现。
在此实例中, Spring Session 由 Redis 支持。
2 我们创建一个RedisConnectionFactory将 Spring Session 连接到 Redis 服务器。
我们将连接配置为在默认端口(6379)上连接到 localhost。
有关配置 Spring 数据 Redis 的更多信息,请参见参考文献 (opens new window)
3 我们定制了 Spring Session 的 HttpSession 集成,以使用 HTTP 头来传递当前会话信息,而不是 Cookie。

# Servlet 容器初始化

我们的Spring Configuration创建了一个名为springSessionRepositoryFilter的 Spring Bean,它实现了FilterspringSessionRepositoryFilter Bean 负责用 Spring Session 支持的自定义实现替换HttpSession

为了使我们的Filter发挥其魔力, Spring 需要加载我们的Config类。我们在我们的 Spring MvcInitializer中提供了配置,如下例所示:

SRC/main/java/sample/mvc/mvcinitializer.java

@Override
protected Class<?>[] getRootConfigClasses() {
	return new Class[] { SecurityConfig.class, HttpSessionConfig.class };
}

最后,我们需要确保我们的 Servlet 容器(即 Tomcat)为每个请求使用我们的springSessionRepositoryFilter。幸运的是, Spring Session 提供了一个名为AbstractHttpSessionApplicationInitializer的实用程序类,这使得这样做很容易。为此,使用默认构造函数扩展类,如下例所示:

SRC/main/java/sample/initializer.java

public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
我们类的名称(Initializer)并不重要。重要的是,我们扩展AbstractHttpSessionApplicationInitializer

# 使用HttpSessionListener

Spring 通过声明SessionEventHttpSessionListenerAdapterSessionDestroyedEventSessionCreatedEvent转换为HttpSessionEvent,会话支持HttpSessionListener。要使用此支持,你需要:

  • 确保你的SessionRepository实现支持并配置为发射SessionDestroyedEventSessionCreatedEvent

  • SessionEventHttpSessionListenerAdapter配置为 Spring Bean。

  • 将每个HttpSessionListener注入SessionEventHttpSessionListenerAdapter

如果你使用[HttpSessionwith Redis](#HttpSession-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"/>