跳到主要内容

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
}

}
java
  • @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,它实现了 FilterspringSessionRepositoryFilter 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
}

}
java
备注

我们类的名称(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"/>
xml
  • 我们使用 <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,它实现了 FilterspringSessionRepositoryFilter 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>
xml

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>
xml

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
}

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

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

会话序列化机制

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

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

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

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

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

通过创建以下bean:

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

…​你可以从默认的(基于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[]
java
JdkMongoSessionConverter

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

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

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
}

}
java
  • @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,它实现了 FilterspringSessionRepositoryFilter 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
}

}
java
备注

我们的类名(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() {
// ...
}
}
java
  • 这个限定符声明 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>
xml
  • 我们使用 <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,它实现了 FilterspringSessionRepositoryFilter 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>
xml

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>
xml

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,它实现了 FilterspringSessionRepositoryFilter 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
}

}
java
  • @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,它实现了 FilterspringSessionRepositoryFilter bean 负责用一个由 Spring Session 支持的自定义实现来替换 HttpSession

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

public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {

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

}
java

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

public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
java
备注

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

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

HttpSession 集成的工作原理

幸运的是,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 ...
}
java

任何返回 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);
}

// ...
}
java

通过将自定义的 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
}

}
java
  • @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,它实现了 FilterspringSessionRepositoryFilter bean 负责将 HttpSession 替换为由 Spring Session 支持的自定义实现。

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

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

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

public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
java
备注

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

使用 HttpSessionListener

Spring Session 通过声明 SessionEventHttpSessionListenerAdapterSessionDestroyedEventSessionCreatedEvent 转换为 HttpSessionEvent 来支持 HttpSessionListener。要使用此支持,您需要:

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

  • 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();
}

// ...

}
java

在 XML 配置中,这可能看起来如下:

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