HttpSession
Integration
Spring Session 与 HttpSession
提供透明集成。这意味着开发人员可以将 HttpSession
实现替换为由 Spring Session 支持的实现。
Why Spring Session and HttpSession
?
我们已经提到 Spring Session 与 HttpSession
提供透明集成,但我们从中获得了哪些好处?
-
Clustered Sessions: Spring 会话轻松支持clustered sessions,而无需绑定到特定于应用程序容器的解决方案。
-
RESTful APIs: Spring 会话允许在标头中提供会话 ID 以配合RESTful APIs工作
HttpSession
with Redis
在 HttpSession
中使用 Spring Session 是通过在所有使用 HttpSession
的内容之前添加 Servlet Filter 来实现的。您可以选择通过使用以下任一种方式来启用此功能:
Redis Java-based Configuration
本节介绍如何使用基于 Java 的配置通过 Redis 来支持 HttpSession
。
HttpSession Sample 提供了一个关于如何通过 Java 配置整合 Spring Session 和 |
@11
Redis XML-based Configuration
本节介绍如何使用基于 XML 的配置通过 Redis 来支持 HttpSession
。
HttpSession XML Sample 提供了一个关于如何通过 XML 配置整合 Spring Session 和 |
@12
HttpSession with Mongo
使用 `HttpSession`的 Spring Session 可通过在使用 `HttpSession`的任何内容之前添加一个 Servlet 过滤器来启用。
本部分介绍如何使用 Mongo 来基于 Java 配置支持 HttpSession
。
HttpSession Mongo Sample 提供了一个使用 Java 配置集成 Spring Session 和 |
@13
Session serialization mechanisms
为了能够在 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 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 序列化以二进制形式将会话属性映射持久性存储在 MongoDB 中。然而,诸如 id、访问时间等标准会话元素仍作为普通的 Mongo 对象进行写入,并且可以在不需要额外工作的情况下进行读取和查询。如果未定义显式的 AbstractMongoSessionConverter
Bean,将使用 JdkMongoSessionConverter
。
还存在一个使用 Serializer
和 Deserializer
对象的构造函数,它允许你传递自定义实现,这在想要使用非默认类加载器时尤为重要。
HttpSession
with JDBC
你可以通过在使用 `HttpSession`的任何内容之前添加一个 Servlet 过滤器来使用 `HttpSession`的 Spring Session。你可以使用以下任何一种方式:
JDBC Java-based Configuration
本部分介绍了在使用基于 Java 的配置时如何使用关系数据库来支持 HttpSession
。
HttpSession JDBC Sample 提供了一个关于如何通过 Java 配置整合 Spring Session 和 |
@14
JDBC XML-based Configuration
本节介绍了在基于 XML 的配置中使用关系数据库作为 HttpSession
的方法。
HttpSession JDBC XML Sample 提供了一个关于如何通过 XML 配置整合 Spring Session 和 |
@15
JDBC Spring Boot-based Configuration
本节介绍了在使用 Spring Boot 时如何使用关系数据库作为 HttpSession
的后盾。
HttpSession JDBC Spring Boot Sample 提供了一个关于如何通过 Spring Boot 整合 Spring Session 和 |
@16
HttpSession with Hazelcast
使用 `HttpSession`的 Spring Session 可通过在使用 `HttpSession`的任何内容之前添加一个 Servlet 过滤器来启用。
本节介绍了如何使用基于 Java 的配置,使用 Hazelcast 来支持 HttpSession
。
Hazelcast Spring Sample 提供了一个工作示例,演示如何通过使用 Java 配置整合 Spring Session 和 |
@17
How HttpSession
Integration Works
幸运的是,HttpSession
和 HttpServletRequest
(用于获取一个 HttpSession
的 API)都是接口。这意味着我们为每个 API 提供我们自己的实现。
本节介绍了 Spring Session 如何提供与 |
首先,我们创建一个自定义的 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 会话的 SessionRepositoryFilter
放在与 HttpSession
交互的任何内容之前非常重要的原因。
HttpSession
and RESTful APIs
Spring 会话可以通过让会话在标题中提供来处理 RESTful API。
REST Sample 提供了一个工作示例,演示如何在 REST 应用程序中使用 Spring Session 以支持通过标头进行身份验证。在接下来的部分中,你可以按照所述的基本整合步骤进行操作,但是我们建议你在与自己的应用程序整合时使用详细的 REST 指南。 |
@18
Using HttpSessionListener
Spring 会话通过将 SessionDestroyedEvent
和 SessionCreatedEvent
转换为 HttpSessionEvent
,并声明 SessionEventHttpSessionListenerAdapter
来支持 HttpSessionListener
。要使用此支持,您需要:
-
确保您的`SessionRepository`实现支持并配置为触发`SessionDestroyedEvent`和`SessionCreatedEvent`。
-
将`SessionEventHttpSessionListenerAdapter`配置为 Spring Bean。
-
在
HttpSessionListener
中注入每个SessionEventHttpSessionListenerAdapter
如果您使用 Redis 支持,将 enableIndexingAndEvents
设置为 true
、@EnableRedisHttpSession(enableIndexingAndEvents = true)
,您所要做的就是将每个 HttpSessionListener
注册为一个 Bean。例如,假设您希望支持 Spring Security 的并发控制,并且需要使用 HttpSessionEventPublisher
。在这种情况下,您可以将 HttpSessionEventPublisher
添加为一个 Bean。在 Java 配置中,这可能如下所示:
/*
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package docs.http;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
// tag::config[]
@Configuration
@EnableRedisHttpSession
public class RedisHttpSessionConfig {
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
// ...
}
// end::config[]
在 XML 配置中,这可能如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-4.1.xsd">
<!-- tag::config[] -->
<bean class="org.springframework.security.web.session.HttpSessionEventPublisher"/>
<!-- end::config[] -->
<context:annotation-config/>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisIndexedHttpSessionConfiguration"/>
<bean class="docs.http.AbstractHttpSessionListenerTests"
factory-method="createMockRedisConnection"/>
<bean class="docs.http.AbstractHttpSessionListenerTests$SecuritySessionDestroyedListener"/>
</beans>