跳到主要内容
版本:3.4.2

HttpSession 集成

QWen Max 中英对照 HttpSession Integration HttpSession Integration

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

为什么选择 Spring Session 和 HttpSession?​

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

  • 集群会话: Spring Session 使支持集群会话变得非常简单,而无需依赖特定于应用容器的解决方案。

  • RESTful APIs: Spring Session 使在头部提供会话 ID 能够与 RESTful APIs 一起工作。

HttpSession 与 Redis​

通过在使用 HttpSession 的任何组件之前添加一个 Servlet 过滤器,可以启用与 HttpSession 一起使用 Spring Session。你可以选择以下任一方式来启用此功能:

基于 Java 的 Redis 配置​

本节介绍如何使用基于 Java 的配置通过 Redis 来支持 HttpSession。

备注

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

Spring Java 配置​

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

@Configuration(proxyBeanMethods = false)
@EnableRedisHttpSession 1
public class Config {

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

}
  • @EnableRedisHttpSession 注解创建了一个名为 springSessionRepositoryFilter 的 Spring Bean,该 Bean 实现了 Filter。该过滤器负责将 HttpSession 实现替换为由 Spring Session 支持的实现。在这种情况下,Spring Session 由 Redis 支持。

  • 我们创建了一个 RedisConnectionFactory,它将 Spring Session 连接到 Redis 服务器。我们配置连接以在默认端口(6379)上连接到本地主机。有关配置 Spring Data Redis 的更多信息,请参阅 参考文档。

Java Servlet 容器初始化​

我们的 Spring 配置 创建了一个名为 springSessionRepositoryFilter 的 Spring Bean,它实现了 Filter。springSessionRepositoryFilter bean 负责用一个由 Spring Session 支持的自定义实现来替换 HttpSession。

为了让我们的 Filter 发挥作用,Spring 需要加载我们的 Config 类。最后,我们需要确保我们的 Servlet 容器(即 Tomcat)对每个请求都使用我们的 springSessionRepositoryFilter。幸运的是,Spring Session 提供了一个名为 AbstractHttpSessionApplicationInitializer 的工具类,使得这两个步骤变得简单。以下是一个示例:

public class Initializer extends AbstractHttpSessionApplicationInitializer { 1

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

}
备注

我们类的名称(Initializer)并不重要。重要的是我们继承了 AbstractHttpSessionApplicationInitializer。

  • 第一步是扩展 AbstractHttpSessionApplicationInitializer。这样做可以确保名为 springSessionRepositoryFilter 的 Spring Bean 被注册到我们的 Servlet 容器中,以便处理每个请求。

  • 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配置:

// <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"/>
  • 我们使用 <context:annotation-config/> 和 RedisHttpSessionConfiguration 的组合,因为 Spring Session 尚未提供 XML 命名空间支持(参见 gh-104)。这会创建一个名为 springSessionRepositoryFilter 的 Spring Bean,该 Bean 实现了 Filter。过滤器负责将 HttpSession 实现替换为由 Spring Session 支持的实现。在这种情况下,Spring Session 由 Redis 支持。

  • 我们创建了一个 RedisConnectionFactory,用于将 Spring Session 连接到 Redis 服务器。我们配置连接以连接到默认端口(6379)上的本地主机。有关配置 Spring Data Redis 的更多信息,请参阅 参考文档。

XML Servlet 容器初始化​

我们在Spring 配置中创建了一个名为 springSessionRepositoryFilter 的 Spring Bean,它实现了 Filter。springSessionRepositoryFilter bean 负责将 HttpSession 替换为由 Spring Session 支持的自定义实现。

为了让我们的 Filter 发挥作用,我们需要指示 Spring 加载我们的 session.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 配置。

最后,我们需要确保我们的 Servlet 容器(即 Tomcat)对每个请求都使用我们的 springSessionRepositoryFilter。以下代码片段为我们完成了这最后一步:

<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 会查找名为 springSessionRepositoryFilter 的 Bean 并将其转换为 Filter。对于每次调用 DelegatingFilterProxy 的请求,都会调用 springSessionRepositoryFilter。

HttpSession with Mongo​

通过在使用 HttpSession 的任何组件之前添加一个 Servlet 过滤器,可以启用与 HttpSession 一起使用 Spring Session。

本节介绍如何使用基于 Java 的配置通过 Mongo 支持 HttpSession。

备注

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

你只需要添加以下 Spring 配置:

@Configuration(proxyBeanMethods = false)
@EnableMongoHttpSession 1
public class HttpSessionConfig {

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

}
  • @EnableMongoHttpSession 注解创建了一个名为 springSessionRepositoryFilter 的 Spring Bean,该 Bean 实现了 Filter 接口。这个过滤器将默认的 HttpSession 替换为基于 MongoDB 的 Bean。

  • 将会话超时时间配置为 30 分钟。

会话序列化机制​

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

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

但是,您只需在 Boot 应用程序中添加以下代码即可切换到 JacksonMongoSessionConverter:

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

这种机制使用 Jackson 将会话对象序列化为 JSON,或者从 JSON 反序列化为会话对象。

通过创建以下bean:

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

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

important

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

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

Unresolved include directive in modules/ROOT/pages/http-session.adoc - include::example$spring-session-data-mongodb-dir/src/integration-test/java/org/springframework/session/data/mongo/integration/MongoRepositoryJacksonITest.java[]
JdkMongoSessionConverter​

JdkMongoSessionConverter 使用标准的 Java 序列化将 session 属性映射以二进制形式持久化到 MongoDB。然而,像 id、访问时间等标准 session 元素仍然以普通的 Mongo 对象形式写入,并且无需额外操作即可读取和查询。如果没有定义明确的 AbstractMongoSessionConverter Bean,则使用 JdkMongoSessionConverter。

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

HttpSession 与 JDBC​

您可以通过在使用 HttpSession 之前的任何地方添加一个 servlet 过滤器来将 Spring Session 与 HttpSession 一起使用。您可以选择以下任何一种方式来实现:

基于 JDBC 的 Java 配置​

本节介绍如何在使用基于 Java 的配置时,使用关系型数据库来支持 HttpSession。

备注

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

Spring Java 配置​

在添加了所需的依赖项之后,我们可以创建我们的Spring配置。Spring配置负责创建一个Servlet Filter,该过滤器将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
}

}
  • @EnableJdbcHttpSession 注解创建了一个名为 springSessionRepositoryFilter 的 Spring Bean。该 Bean 实现了 Filter。过滤器负责将 HttpSession 实现替换为由 Spring Session 支持的实现。在这种情况下,Spring Session 由关系型数据库支持。

  • 我们创建了一个 dataSource,它将 Spring Session 连接到 H2 数据库的一个嵌入实例。我们配置 H2 数据库以使用包含在 Spring Session 中的 SQL 脚本来创建数据库表。

  • 我们创建了一个 transactionManager,用于管理之前配置的 dataSource 的事务。

有关如何配置与数据访问相关的问题的更多信息,请参见 Spring 框架参考文档。

Java Servlet 容器初始化​

我们的 Spring 配置 创建了一个名为 springSessionRepositoryFilter 的 Spring bean,它实现了 Filter。springSessionRepositoryFilter bean 负责将 HttpSession 替换为由 Spring Session 支持的自定义实现。

为了让我们的 Filter 发挥作用,Spring 需要加载我们的 Config 类。最后,我们需要确保我们的 Servlet 容器(即 Tomcat)对每个请求都使用我们的 springSessionRepositoryFilter。幸运的是,Spring Session 提供了一个名为 AbstractHttpSessionApplicationInitializer 的工具类,使得这两个步骤变得简单。下面的示例展示了如何实现这一点:

public class Initializer extends AbstractHttpSessionApplicationInitializer { 1

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

}
备注

我们的类名(Initializer)并不重要。重要的是我们继承了 AbstractHttpSessionApplicationInitializer。

  • 第一步是扩展 AbstractHttpSessionApplicationInitializer。这样做可以确保名为 springSessionRepositoryFilter 的 Spring bean 对每个请求都在我们的 Servlet 容器中注册。

  • AbstractHttpSessionApplicationInitializer 还提供了一种机制,以确保 Spring 加载我们的 Config。

多个数据源​

Spring Session 提供了 @SpringSessionDataSource 限定符,允许你显式声明应注入到 JdbcIndexedSessionRepository 中的 DataSource bean。这在应用程序上下文中存在多个 DataSource bean 的情况下特别有用。

以下示例展示了如何这样做:

@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() {
// ...
}
}
  • 这个限定符声明 firstDataSource 将被 Spring Session 使用。

基于 JDBC 的 XML 配置​

本节描述了如何在使用基于 XML 的配置时,使用关系型数据库来支持 HttpSession。

备注

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

Spring XML 配置​

在添加了所需的依赖项后,我们可以创建我们的Spring配置。Spring配置负责创建一个Servlet过滤器,该过滤器将HttpSession实现替换为由Spring Session支持的实现。以下清单展示了如何添加以下Spring配置:

// <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>
  • 我们使用 <context:annotation-config/> 和 JdbcHttpSessionConfiguration 的组合,因为 Spring Session 尚未提供 XML 命名空间支持(参见 gh-104)。这会创建一个名为 springSessionRepositoryFilter 的 Spring bean。该 bean 实现了 Filter。过滤器负责将 HttpSession 实现替换为由 Spring Session 支持的实现。在这种情况下,Spring Session 由关系数据库支持。

  • 我们创建了一个 dataSource,它将 Spring Session 连接到 H2 数据库的嵌入实例。我们配置 H2 数据库以使用包含在 Spring Session 中的 SQL 脚本来创建数据库表。

  • 我们创建了一个 transactionManager,用于管理之前配置的 dataSource 的事务。

有关如何配置与数据访问相关的设置的更多信息,请参见 Spring 框架参考文档。

XML Servlet 容器初始化​

我们在Spring 配置中创建了一个名为 springSessionRepositoryFilter 的 Spring bean,它实现了 Filter。springSessionRepositoryFilter bean 负责将 HttpSession 替换为由 Spring Session 支持的自定义实现。

为了让我们的 Filter 发挥作用,我们需要指示 Spring 加载我们的 session.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 配置。

最后,我们需要确保我们的 Servlet 容器(即 Tomcat)对每个请求都使用我们的 springSessionRepositoryFilter。以下代码片段为我们完成了这最后一步:

<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 查找名为 springSessionRepositoryFilter 的 bean 并将其转换为 Filter。对于调用 DelegatingFilterProxy 的每个请求,都会调用 springSessionRepositoryFilter。

基于JDBC的Spring Boot配置​

本节介绍如何在使用 Spring Boot 时使用关系型数据库来支持 HttpSession。

备注

HttpSession JDBC Spring Boot Sample 提供了一个如何使用 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。过滤器负责将 HttpSession 实现替换为由 Spring Session 支持的实现。

你可以通过使用 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 Session 部分的 Spring Boot 文档。

配置 DataSource​

Spring Boot 会自动创建一个 DataSource,将 Spring Session 连接到 H2 数据库的嵌入式实例。在生产环境中,你需要更新配置以指向你的关系型数据库。例如,你可以在 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部分。

Servlet 容器初始化​

我们的 Spring Boot 配置 创建了一个名为 springSessionRepositoryFilter 的 Spring bean,它实现了 Filter。springSessionRepositoryFilter bean 负责将 HttpSession 替换为由 Spring Session 支持的自定义实现。

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

使用 Hazelcast 的 HttpSession​

通过在使用 HttpSession 的任何组件之前添加一个 Servlet 过滤器,可以启用与 HttpSession 一起使用 Spring Session。

本节介绍如何使用基于 Java 的配置通过 Hazelcast 来支持 HttpSession。

备注

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

Spring 配置​

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

@EnableHazelcastHttpSession 1
@Configuration
public class HazelcastHttpSessionConfig {

@Bean
public HazelcastInstance hazelcastInstance() {
Config config = new Config();
AttributeConfig attributeConfig = new AttributeConfig()
.setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
.setExtractorClassName(PrincipalNameExtractor.class.getName());
config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) 2
.addAttributeConfig(attributeConfig)
.addIndexConfig(
new IndexConfig(IndexType.HASH, HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE));
SerializerConfig serializerConfig = new SerializerConfig();
serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class);
config.getSerializationConfig().addSerializerConfig(serializerConfig); 3
return Hazelcast.newHazelcastInstance(config); 4
}

}
  • @EnableHazelcastHttpSession 注解创建了一个名为 springSessionRepositoryFilter 的 Spring bean,该 bean 实现了 Filter。此过滤器负责将 HttpSession 的实现替换为由 Spring Session 支持的实现。在这种情况下,Spring Session 由 Hazelcast 支持。

  • 为了支持通过主体名称索引检索会话,需要注册适当的 ValueExtractor。Spring Session 为此提供了 PrincipalNameExtractor。

  • 为了高效地序列化 MapSession 对象,需要注册 HazelcastSessionSerializer。如果未设置此项,Hazelcast 将使用原生 Java 序列化来序列化会话。

  • 我们创建了一个 HazelcastInstance,将 Spring Session 连接到 Hazelcast。默认情况下,应用程序启动并连接到嵌入式的 Hazelcast 实例。有关配置 Hazelcast 的更多信息,请参阅 参考文档。

备注

如果更倾向于使用 HazelcastSessionSerializer,则需要在所有 Hazelcast 集群成员启动之前为其配置。在 Hazelcast 集群中,所有成员应使用相同的会话序列化方法。另外,如果使用的是 Hazelcast 客户端/服务器拓扑结构,则成员和客户端都必须使用相同的序列化方法。可以通过 ClientConfig 以与成员相同的 SerializerConfiguration 注册序列化器。

Servlet 容器初始化​

我们的 Spring 配置 创建了一个名为 springSessionRepositoryFilter 的 Spring bean,它实现了 Filter。springSessionRepositoryFilter bean 负责用一个由 Spring Session 支持的自定义实现来替换 HttpSession。

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

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {

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

}

最后,我们需要确保我们的 Servlet 容器(即 Tomcat)对每个请求都使用我们的 springSessionRepositoryFilter。非常重要的一点是,Spring Session 的 springSessionRepositoryFilter 必须在 Spring Security 的 springSecurityFilterChain 之前被调用。这样做可以确保 Spring Security 使用的 HttpSession 是由 Spring Session 支持的。幸运的是,Spring Session 提供了一个名为 AbstractHttpSessionApplicationInitializer 的工具类,使得这样做变得容易。以下示例展示了如何实现这一点:

public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
备注

我们的类名(Initializer)并不重要。重要的是我们继承了 AbstractHttpSessionApplicationInitializer。

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

HttpSession 集成的工作原理​

幸运的是,HttpSession 和 HttpServletRequest(用于获取 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 APIs​

Spring Session 可以通过让会话在头部提供来与 RESTful API 协作。

备注

REST 示例 提供了一个如何在 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
}

}
  • @EnableRedisHttpSession 注解创建了一个名为 springSessionRepositoryFilter 的 Spring bean,该 bean 实现了 Filter。此过滤器负责将 HttpSession 的实现替换为由 Spring Session 支持的实现。在这种情况下,Spring Session 由 Redis 支持。

  • 我们创建了一个 RedisConnectionFactory,用于将 Spring Session 连接到 Redis 服务器。我们配置连接以默认端口(6379)连接到本地主机。有关配置 Spring Data Redis 的更多信息,请参阅参考文档。

  • 我们自定义了 Spring Session 的 HttpSession 集成,使用 HTTP 头来传递当前会话信息,而不是使用 cookie。

Servlet 容器初始化​

我们的 Spring 配置 创建了一个名为 springSessionRepositoryFilter 的 Spring Bean,它实现了 Filter。springSessionRepositoryFilter bean 负责将 HttpSession 替换为由 Spring Session 支持的自定义实现。

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

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

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

public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
备注

我们的类的名称(Initializer)并不重要。重要的是我们继承了 AbstractHttpSessionApplicationInitializer。

使用 HttpSessionListener​

Spring Session 通过声明 SessionEventHttpSessionListenerAdapter 将 SessionDestroyedEvent 和 SessionCreatedEvent 转换为 HttpSessionEvent 来支持 HttpSessionListener。要使用此支持,您需要:

  • 确保你的 SessionRepository 实现支持并配置为触发 SessionDestroyedEvent 和 SessionCreatedEvent。

  • 将 SessionEventHttpSessionListenerAdapter 配置为 Spring bean。

  • 将每个 HttpSessionListener 注入到 SessionEventHttpSessionListenerAdapter 中。

如果你使用 Redis 支持并将 enableIndexingAndEvents 设置为 true,@EnableRedisHttpSession(enableIndexingAndEvents = true),你所需要做的就是将每个 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"/>