HttpSession
集成
Spring Session 提供与 HttpSession
的透明集成。这意味着开发人员可以使用由 Spring Session 支持的实现来替换 HttpSession
实现。
为什么选择 Spring Session 和 HttpSession
?
我们已经提到 Spring Session 提供与 HttpSession
的透明集成,但我们从中获得了什么好处呢?
-
集群会话:Spring Session 使支持 集群会话 变得非常容易,而无需绑定到特定于应用程序容器的解决方案。
-
RESTful API:Spring Session 允许在标头中提供会话 ID,以便与 RESTful API 协同工作。
HttpSession
与 Redis
使用 Spring Session 与 HttpSession
需要在使用 HttpSession
的任何内容之前添加一个 Servlet 过滤器。您可以选择通过以下两种方式启用此功能:
Redis 基于 Java 的配置
本节介绍如何使用基于 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)
}
}
1 | @EnableRedisHttpSession 注解创建一个名为 springSessionRepositoryFilter 的 Spring Bean,该 Bean 实现 Filter 。该过滤器负责替换 HttpSession 实现,使其由 Spring Session 支持。在本例中,Spring Session 由 Redis 支持。 |
2 | 我们创建一个 RedisConnectionFactory ,将 Spring Session 连接到 Redis 服务器。我们配置连接以连接到默认端口 (6379) 上的 localhost。有关配置 Spring Data Redis 的更多信息,请参阅 参考文档。 |
Java Servlet 容器初始化
我们的 Spring 配置 创建了一个名为 springSessionRepositoryFilter
的 Spring Bean,该 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 。
|
1 | 第一步是扩展AbstractHttpSessionApplicationInitializer 。这样做可以确保名为springSessionRepositoryFilter 的 Spring Bean 在每个请求中都注册到我们的 Servlet 容器。 |
2 | AbstractHttpSessionApplicationInitializer 还提供了一种机制来确保 Spring 加载我们的Config 。 |
基于 XML 的 Redis 配置
本节介绍如何使用 Redis 通过基于 XML 的配置来支持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"/>
1 | 我们使用<context:annotation-config/> 和 RedisHttpSessionConfiguration 的组合,因为 Spring Session 尚未提供 XML 命名空间支持(参见gh-104)。这将创建一个名为springSessionRepositoryFilter 的 Spring Bean,它实现了Filter 。该过滤器负责替换HttpSession 实现,使其由 Spring Session 支持。在本例中,Spring Session 由 Redis 支持。 |
2 | 我们创建了一个RedisConnectionFactory ,它将 Spring Session 连接到 Redis 服务器。我们配置连接以连接到默认端口(6379)上的 localhost。有关配置 Spring Data Redis 的更多信息,请参见参考文档。 |
XML Servlet 容器初始化
我们的Spring 配置创建了一个名为springSessionRepositoryFilter
的 Spring Bean,它实现了Filter
。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 配置文件。
最后,我们需要确保我们的 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
。
使用 Mongo 的 HttpSession
通过在使用 HttpSession
的任何内容之前添加一个 Servlet 过滤器,可以启用使用 Spring Session 的 HttpSession
。
本节介绍如何使用 Java 基于配置的方式使用 Mongo 来支持 HttpSession
。
HttpSession Mongo 示例 提供了一个使用 Java 配置集成 Spring Session 和 HttpSession 的工作示例。 你可以阅读下面的基本集成步骤,但建议你在将 Spring Session 集成到自己的应用程序时,参考详细的 HttpSession 指南。
|
你只需要添加以下 Spring 配置。
@Configuration(proxyBeanMethods = false)
@EnableMongoHttpSession (1)
public class HttpSessionConfig {
@Bean
public JdkMongoSessionConverter jdkMongoSessionConverter() {
return new JdkMongoSessionConverter(Duration.ofMinutes(30)); (2)
}
}
1 | @EnableMongoHttpSession 注解会创建一个名为 springSessionRepositoryFilter 的 Spring Bean,该 Bean 实现 Filter 接口。 该过滤器会用 MongoDB 支持的 Bean 替换默认的 HttpSession 。 |
2 | 将会话超时时间配置为 30 分钟。 |
会话序列化机制
为了能够将会话对象持久化到 MongoDB 中,我们需要提供序列化/反序列化机制。
默认情况下,Spring Session MongoDB 会使用 JdkMongoSessionConverter
。
但是,你可以通过在 Boot 应用程序中添加以下代码来切换到 JacksonMongoSessionConverter
。
@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
return new JacksonMongoSessionConverter();
}
JacksonMongoSessionConverter
该机制使用 Jackson 将会话对象序列化/反序列化为 JSON。
通过创建以下 Bean
@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
return new JacksonMongoSessionConverter();
}
…你可以从默认的(基于 JDK 的序列化)切换到使用 Jackson。
如果你将 Spring Session 与 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[]
HttpSession
与 JDBC
您可以通过在使用 HttpSession
的任何内容之前添加一个 servlet 过滤器来使用 Spring Session 与 HttpSession
。您可以选择以下任何一种方式进行操作。
基于 JDBC 的 Java 配置
本节介绍如何在使用基于 Java 的配置时使用关系数据库来支持 HttpSession
。
该 HttpSession JDBC 示例 提供了一个关于如何通过使用 Java 配置来集成 Spring Session 和 HttpSession 的工作示例。您可以阅读以下几节中关于集成的基本步骤,但我们建议您在与自己的应用程序集成时,遵循详细的 HttpSession JDBC 指南。
|
Spring Java 配置
添加了必要的依赖项后,我们可以创建 Spring 配置。Spring 配置负责创建一个 Servlet 过滤器,该过滤器将 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 。该过滤器负责将 HttpSession 实现替换为由 Spring Session 支持的实现。在本例中,Spring Session 由关系数据库支持。 |
2 | 我们创建一个 dataSource ,它将 Spring Session 连接到嵌入式 H2 数据库实例。我们配置 H2 数据库以使用 Spring Session 中包含的 SQL 脚本创建数据库表。 |
3 | 我们创建一个 transactionManager ,它管理先前配置的 dataSource 的事务。 |
有关如何配置数据访问相关问题的更多信息,请参阅Spring 框架参考文档。
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 。
|
1 | 第一步是扩展AbstractHttpSessionApplicationInitializer 。这样做可以确保名为springSessionRepositoryFilter 的 Spring bean 为每个请求注册到我们的 Servlet 容器。 |
2 | 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() {
// ...
}
}
1 | 此限定符声明 firstDataSource 将由 Spring Session 使用。 |
基于 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>
1 | 我们使用<context:annotation-config/> 和JdbcHttpSessionConfiguration 的组合,因为 Spring Session 尚未提供 XML 命名空间支持(请参阅gh-104)。这将创建一个名为springSessionRepositoryFilter 的 Spring bean。该 bean 实现Filter 。该过滤器负责替换由 Spring Session 支持的HttpSession 实现。在本例中,Spring Session 由关系数据库支持。 |
2 | 我们创建一个 dataSource ,它将 Spring Session 连接到嵌入式 H2 数据库实例。我们配置 H2 数据库以使用 Spring Session 中包含的 SQL 脚本创建数据库表。 |
3 | 我们创建一个 transactionManager ,它管理先前配置的 dataSource 的事务。 |
有关如何配置数据访问相关问题的更多信息,请参阅Spring 框架参考文档。
XML Servlet 容器初始化
我们的Spring 配置创建了一个名为springSessionRepositoryFilter
的 Spring bean,它实现了Filter
。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 配置。
最后,我们需要确保我们的 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 示例提供了一个关于如何使用 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
进行进一步自定义。以下清单展示了如何操作。
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 自动创建一个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 负责用 Spring Session 支持的自定义实现替换HttpSession
。
为了让我们的Filter
发挥作用,Spring 需要加载我们的Config
类。最后,我们需要确保我们的 Servlet 容器(即 Tomcat)对每个请求都使用我们的springSessionRepositoryFilter
。幸运的是,Spring Boot 为我们处理了这两个步骤。
使用 Hazelcast 的 HttpSession
通过在使用 HttpSession
的任何内容之前添加一个 Servlet 过滤器,可以启用使用 Spring Session 的 HttpSession
。
本节介绍如何使用基于 Java 的配置将 Hazelcast 用作HttpSession
的后端。
Hazelcast Spring 示例 提供了一个使用 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();
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)
}
}
1 | @EnableHazelcastHttpSession 注解创建一个名为springSessionRepositoryFilter 的 Spring bean,它实现了Filter 。该过滤器负责替换HttpSession 实现,使其由 Spring Session 支持。在本例中,Spring Session 由 Hazelcast 支持。 |
2 | 为了支持通过主体名称索引检索会话,需要注册一个合适的ValueExtractor 。Spring Session为此提供了PrincipalNameExtractor 。 |
3 | 为了有效地序列化MapSession 对象,需要注册HazelcastSessionSerializer 。如果没有设置,Hazelcast将使用原生Java序列化来序列化会话。 |
4 | 我们创建一个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 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)
}
}
1 | @EnableRedisHttpSession 注解创建了一个名为 springSessionRepositoryFilter 的 Spring bean,它实现了 Filter 。该过滤器负责替换 HttpSession 实现,使其由 Spring Session 支持。在本例中,Spring Session 由 Redis 支持。 |
2 | 我们创建一个 RedisConnectionFactory ,将 Spring Session 连接到 Redis 服务器。我们配置连接以连接到默认端口 (6379) 上的 localhost。有关配置 Spring Data Redis 的更多信息,请参阅 参考文档。 |
3 | 我们自定义 Spring Session 的 HttpSession 集成,以使用 HTTP 标头来传递当前会话信息,而不是使用 cookie。 |
Servlet 容器初始化
我们的 Spring 配置 创建了一个名为 springSessionRepositoryFilter
的 Spring Bean,它实现了 Filter
。springSessionRepositoryFilter
bean 负责用由 Spring Session 支持的自定义实现替换 HttpSession
。
为了让我们的 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 通过将 SessionDestroyedEvent
和 SessionCreatedEvent
转换为 HttpSessionEvent
来支持 HttpSessionListener
,方法是声明 SessionEventHttpSessionListenerAdapter
。要使用此支持,您需要
-
确保您的
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"/>