跳到主要内容
版本:4.1.1

HttpSession 集成

Doubao 中英对照 HttpSession Integration

Spring Session 提供与 HttpSession 的透明集成。这意味着开发者可以将 HttpSession 实现替换为由 Spring Session 支撑的实现。

为什么选择 Spring Session 与 HttpSession?​

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

  • 集群会话:Spring Session 让支持集群会话变得非常简单,而且不绑定于任何特定应用容器的解决方案。
  • RESTful API:Spring Session 让在请求头中提供会话 ID 的方式能够与 RESTful API 协同工作。

使用 Redis 作为 HttpSession 的存储​

你可以在任何以下方式中使用 Spring Session 与 HttpSession:

基于 Java 的 Redis 配置​

本节介绍如何使用基于 Java 的配置,以 Redis 作为 HttpSession 的存储。

备注

HttpSession 示例 提供了一个可运行的示例,演示如何使用 Java 配置集成 Spring Session 与 HttpSession。你可以在接下来的几节中阅读集成的基本步骤,但我们鼓励你在将其集成到自己的应用程序时,跟随详细的 HttpSession 指南一起操作。

Spring Java 配置​

添加所需依赖后,我们就可以创建 Spring 配置。Spring 配置负责创建一个 servlet 过滤器,用由 Spring Session 支撑的实现替换 HttpSession 实现。为此,添加以下 Spring 配置:

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

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

}
  • @EnableRedisHttpSession 注解创建了一个名为 springSessionRepositoryFilter、实现了 Filter 的 Spring Bean。该过滤器负责替换 HttpSession 实现,使其由 Spring Session 支撑。在本例中,Spring Session 由 Redis 支撑。

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

Java Servlet 容器初始化​

我们的 Spring 配置 创建了一个名为 springSessionRepositoryFilter、实现了 Filter 的 Spring Bean。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 过滤器,用由 Spring Session 支撑的实现替换 HttpSession 实现。为此,添加以下 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、实现了 Filter 的 Spring Bean。该过滤器负责替换 HttpSession 实现,使其由 Spring Session 支撑。在本例中,Spring Session 由 Redis 支撑。

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

XML Servlet 容器初始化​

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

为了让我们的 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 配置。

<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 作为 HttpSession 的存储​

你可以在任何以下方式中使用 Spring Session 与 HttpSession:

基于 Java 的 JDBC 配置​

本节介绍在使用基于 Java 的配置时,如何使用关系数据库作为 HttpSession 的存储。

备注

HttpSession JDBC 示例 提供了一个可运行的示例,演示如何使用 Java 配置集成 Spring Session 与 HttpSession。你可以在接下来的几节中阅读集成的基本步骤,但我们鼓励你在将其集成到自己的应用程序时,跟随详细的 HttpSession JDBC 指南一起操作。

Spring Java 配置​

添加所需依赖后,我们就可以创建 Spring 配置。Spring 配置负责创建一个 Servlet 过滤器,用由 Spring Session 支撑的实现替换 HttpSession 实现。为此,添加以下 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 Framework 参考文档。

Java Servlet 容器初始化​

我们的 Spring 配置 创建了一个名为 springSessionRepositoryFilter、实现了 Filter 的 Spring Bean。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。

多 DataSource​

Spring Session 提供了 @SpringSessionDataSource 限定符,让你可以显式声明应将哪个 DataSource bean 注入 JdbcIndexedSessionRepository。当应用上下文中存在多个 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() {
// ...
}
}
  • 该限定符声明 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 配置:

// <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 Framework 参考文档。

XML Servlet 容器初始化​

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

为了让我们的 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 配置。

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

基于 Spring Boot 的 JDBC 配置​

本节介绍在使用 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。该过滤器负责替换 HttpSession 实现,使其由 Spring Session 支撑。

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.

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

更多信息,请参阅 Spring Boot 文档中的 Spring Session 部分。

配置 DataSource​

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、实现了 Filter 的 Spring Bean。springSessionRepositoryFilter bean 负责用由 Spring Session 支撑的自定义实现替换 HttpSession。

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

HttpSession 集成的工作原理​

幸运的是,HttpSession 和 HttpServletRequest(用于获取 HttpSession 的 API)都是接口。这意味着我们可以为这两个 API 各自提供自己的实现。

备注

本节介绍 Spring Session 如何提供与 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 示例 提供了一个可运行的示例,演示如何在 REST 应用程序中使用 Spring Session 来支持通过请求头进行认证。你可以按照接下来几节所述的基本集成步骤操作,但我们鼓励你在将其集成到自己的应用程序时,跟随详细的 REST 指南一起操作。

Spring 配置​

添加所需依赖后,我们就可以创建 Spring 配置。Spring 配置负责创建一个 servlet 过滤器,用由 Spring Session 支撑的实现替换 HttpSession 实现。为此,添加以下 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、实现了 Filter 的 Spring Bean。该过滤器负责替换 HttpSession 实现,使其由 Spring Session 支撑。在本例中,Spring Session 由 Redis 支撑。

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

  • 我们自定义 Spring Session 的 HttpSession 集成,使其使用 HTTP 请求头而非 Cookie 来传递当前会话信息。

Servlet 容器初始化​

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

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

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

}
备注

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

使用 HttpSessionListener​

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

  • 确保你的 SessionRepository 实现支持并已配置为触发 SessionDestroyedEvent 和 SessionCreatedEvent。
  • 将 SessionEventHttpSessionListenerAdapter 配置为一个 Spring bean。
  • 将每个 HttpSessionListener 注入到 SessionEventHttpSessionListenerAdapter 中。
@Configuration
@EnableRedisHttpSession
public class RedisHttpSessionConfig {

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

// ...

}

在 XML 配置中,可能如下所示:

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