|
最新稳定版请使用Spring Session 3.5.3! |
API 文档
你可以在线浏览完整的Javadoc。关键 API 在以下章节中描述:
用会期
一个会期是简化版地图以名称值对命名。
典型用法可能如下:
class RepositoryDemo<S extends Session> {
private SessionRepository<S> repository; (1)
void demo() {
S toSave = this.repository.createSession(); (2)
(3)
User rwinch = new User("rwinch");
toSave.setAttribute(ATTR_USER, rwinch);
this.repository.save(toSave); (4)
S session = this.repository.findById(toSave.getId()); (5)
(6)
User user = session.getAttribute(ATTR_USER);
assertThat(user).isEqualTo(rwinch);
}
// ... setter methods ...
}
| 1 | 我们创建一个会话仓库具有泛型的实例,S,扩展为会期.泛型在我们的类中定义。 |
| 2 | 我们创造一个新的会期通过使用我们的会话仓库并将其赋值为 的变量S. |
| 3 | 我们与会期.在我们的例子中,我们演示了如何节省用户前往会期. |
| 4 | 我们现在拯救会期.这就是为什么我们需要仿制药S.这会话仓库只允许保存会期这些实例是通过相同的会话仓库.这使得会话仓库实现实现特定的优化(即只写变更的属性)。 |
| 5 | 我们取回会期来自会话仓库. |
| 6 | 我们得到持久化的用户来自我们的会期无需明确施放我们的属性。 |
这会期API 还提供与会期实例的过期。
典型用法可能如下:
class ExpiringRepositoryDemo<S extends Session> {
private SessionRepository<S> repository; (1)
void demo() {
S toSave = this.repository.createSession(); (2)
// ...
toSave.setMaxInactiveInterval(Duration.ofSeconds(30)); (3)
this.repository.save(toSave); (4)
S session = this.repository.findById(toSave.getId()); (5)
// ...
}
// ... setter methods ...
}
| 1 | 我们创建一个会话仓库具有泛型的实例,S,扩展为会期.泛型在我们的类中定义。 |
| 2 | 我们创造一个新的会期通过使用我们的会话仓库并将其赋值为 的变量S. |
| 3 | 我们与会期.
在我们的例子中,我们演示了更新会期可以在期限到期前处于非激活状态。 |
| 4 | 我们现在拯救会期.
这就是为什么我们需要通用型,S.
这会话仓库仅允许保存会期这些实例是用相同的方法创建或检索的会话仓库.
这使得会话仓库实现实现特定的优化(即只写变更的属性)。
当会期得救了。 |
| 5 | 我们取回会期来自会话仓库.
如果会期如果已过期,则结果将无效。 |
用会话仓库
一个会话仓库负责创建、检索和持续保存会期实例。
如果可能,你不应直接与会话仓库或者会期.
相反,开发者应该更愿意与会话仓库和会期间接通过HttpSession以及WebSocket集成。
用FindByIndexNameSessionRepository
Spring Session 最基本的 API 用于使用会期是会话仓库.
这个 API 有意设计得非常简单,这样你可以轻松提供具备基础功能的额外实现。
一些会话仓库实现也可以选择实现FindByIndexNameSessionRepository.
例如,Spring的Redis、JDBC和Hazelcast支持库都实现了FindByIndexNameSessionRepository.
这FindByIndexNameSessionRepository提供了查找所有具有给定索引名称和索引值的会话的方法。
作为所有提供的共同用例支持FindByIndexNameSessionRepository实现时,你可以用方便的方法查找特定用户的所有会话。
这通过确保会话属性的名称为FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME该用户名被填充。
确保属性被填充是你的责任,因为 Spring Session 不知道所使用的认证机制。
如何使用这个方法的示例可见以下列表:
String username = "username";
this.session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
一些 的实现FindByIndexNameSessionRepository提供钩子以自动索引其他会话属性。
例如,许多实现会自动确保当前的 Spring Security 用户名被索引为FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME. |
会话被索引后,你可以通过类似以下代码找到:
String username = "username";
Map<String, Session> sessionIdToSession = this.sessionRepository.findByPrincipalName(username);
用ReactiveSessionRepository
一个ReactiveSessionRepository负责创建、检索和持续保存会期以非阻塞且反应的方式进行实例。
如果可能,你不应直接与ReactiveSessionRepository或者会期.
相反,你应该更喜欢与人互动ReactiveSessionRepository和会期通过WebSession集成间接实现。
用@EnableSpringHttpSession
你可以添加@EnableSpringHttpSession注释到@Configuration以暴露SessionRepositoryFilter作为一个名为springSessionRepositoryFilter.
要使用注释,你必须提供一个会话仓库豆。
以下示例展示了如何实现:
@EnableSpringHttpSession
@Configuration
public class SpringHttpSessionConfig {
@Bean
public MapSessionRepository sessionRepository() {
return new MapSessionRepository(new ConcurrentHashMap<>());
}
}
请注意,没有为会话到期配置任何基础设施。 这是因为像会话到期这样的功能高度依赖于实现。 这意味着,如果你需要清理过期的会话,你就有责任清理这些过期的会话。
用@EnableSpringWebSession
你可以添加@EnableSpringWebSession注释到@Configuration以暴露WebSessionManager作为一个名为webSessionManager.
使用注释时,您必须提供一个ReactiveSessionRepository豆。
以下示例展示了如何实现:
@Configuration(proxyBeanMethods = false)
@EnableSpringWebSession
public class SpringWebSessionConfig {
@Bean
public ReactiveSessionRepository reactiveSessionRepository() {
return new ReactiveMapSessionRepository(new ConcurrentHashMap<>());
}
}
请注意,没有为会话到期配置任何基础设施。 这是因为像会话到期这样的功能高度依赖于实现。 这意味着,如果你需要清理过期的会话,你就有责任清理这些过期的会话。
用RedisSession仓库
RedisSession仓库是会话仓库该系统通过使用 Spring Data 实现RedisOperations.
在网络环境中,这通常与以下结合使用。SessionRepositoryFilter.
请注意,该实现不支持发布会话事件。
实例化RedisSession仓库
你可以在以下列表中看到创建新实例的典型示例:
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// ... configure redisTemplate ...
SessionRepository<? extends Session> repository = new RedisSessionRepository(redisTemplate);
关于如何创建RedisConnection工厂,参见Spring Data Redis参考文献。
用@EnableRedisHttpSession
在网络环境中,创建新文件的最简单方式RedisSession仓库是 使用@EnableRedisHttpSession. 你可以在示例和指南(从这里开始)中找到完整的示例使用情况。您可以使用以下属性来自定义配置:
enableIndexingAndEvents
* enableIndexingAndEvents:是否使用RedisIndexedSessionRepository而不是RedisSession仓库. 默认为false.
* maxInactiveIntervalInSeconds:会话结束前的时间,单位为秒。
* redisNamespace:允许为会话配置应用特定的命名空间。Redis 密钥和通道 ID 以 前缀 开头<redisNamespace>:. * flushMode:允许指定何时将数据写入 Redis。默认状态仅在救被调用于会话仓库.
一个值为冲洗模式。立即尽快写信给Redis。
在Redis中查看会话
安装 redis-cli 后,你可以用 redis-cli 检查 Redis 中的数值。 例如,你可以在终端窗口中输入以下命令:
$ redis-cli
redis 127.0.0.1:6379> keys *
1) "spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021" (1)
| 1 | 该密钥的后缀是春季会话的会话标识符。 |
你也可以通过使用赫基斯命令。
以下示例展示了如何实现:
redis 127.0.0.1:6379> hkeys spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021
1) "lastAccessedTime"
2) "creationTime"
3) "maxInactiveInterval"
4) "sessionAttr:username"
redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021 sessionAttr:username
"\xac\xed\x00\x05t\x00\x03rob"
用RedisIndexedSessionRepository
RedisIndexedSessionRepository是会话仓库该系统通过使用 Spring Data 实现RedisOperations.
在网络环境中,这通常与以下结合使用。SessionRepositoryFilter. 实现支持SessionDestroyedEvent和SessionCreatedEvent通过SessionMessageListener(会话信息听听器).
实例化RedisIndexedSessionRepository
你可以在以下列表中看到创建新实例的典型示例:
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// ... configure redisTemplate ...
SessionRepository<? extends Session> repository = new RedisIndexedSessionRepository(redisTemplate);
关于如何创建RedisConnection工厂,参见Spring Data Redis参考文献。
用@EnableRedisHttpSession(enableIndexingAndEvents = true)
在网络环境中,创建新文件的最简单方式RedisIndexedSessionRepository是 使用@EnableRedisHttpSession(enableIndexingAndEvents = true). 你可以在示例和指南(从这里开始)中找到完整的示例使用情况。您可以使用以下属性来自定义配置:
-
enableIndexingAndEvents:是否使用一个
RedisIndexedSessionRepository而不是RedisSession仓库. 默认为false. -
maxInactiveIntervalInSeconds:会话结束前的时间,以秒为单位。
-
redisNamespace:允许为会话配置应用特定的命名空间。Redis 键和通道 ID 以 前缀 开头
<redisNamespace>:. -
flushMode:允许指定何时将数据写入 Redis。默认只有当
救被调用于会话仓库. 一个值为冲洗模式。立即尽快写信给Redis。
Redis任务执行者
RedisIndexedSessionRepository订阅通过使用RedisMessageListenerContainer. 你可以通过创建一个名为springSessionRedisTaskExecutor,一颗豆子springSessionRedisSubscriptionExecutor,或者两者兼有。你可以在这里找到更多关于配置 Redis 任务执行器的细节。
存储详情
以下章节概述了 Redis 如何为每个作更新。以下示例展示了创建新会话的示例:
HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 \ maxInactiveInterval 1800 \ lastAccessedTime 1404360000000 \ sessionAttr:attrName someAttrValue \ sessionAttr:attrName2 someAttrValue2 EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100 APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe "" EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800 SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe EXPIRE spring:session:expirations1439245080000 2100
后续章节将详细说明。
拯救一场游戏
每个会话都存储在 Redis,作为散 列. 每个会话通过使用HMSET命令。 以下示例展示了每个会话的存储方式:
HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 \ maxInactiveInterval 1800 \ lastAccessedTime 1404360000000 \ sessionAttr:attrName someAttrValue \ sessionAttr:attrName2 someAttrValue2
在上述例子中,关于该会话的以下陈述是成立的:
-
会话编号是33fdd1b6-b496-4b33-9f7d-df96679d32fe。
-
会话创建时间为1404360000000点(自1970年1月1日午夜起的毫秒计)。
-
该会话将在1800秒(30分钟)后结束。
-
该会话最后一次访问是在1404360000000点(自1970年1月1日午夜起毫秒计)。
-
会话有两个属性。第一个是
用户名,其值为someAttrValue. 第二个会话属性被命名为收件人姓名2,其值为someAttrValue2.
优化写入
这会期由管理的实例RedisIndexedSessionRepository跟踪已更改的属性,并只更新这些。这意味着,如果一个属性只写一次并多次读取,我们只需写一次该属性。例如,假设收件人姓名2前一节LSITING中的会话属性已更新。保存后将执行以下命令:
HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe sessionAttr:attrName2 newValue
会议期结束
每个会话都关联一个过期,通过使用到期基于Session.getMaxInactiveInterval(). 以下示例展示了一个典型的到期命令:
EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
注意,设定为会话实际到期后五分钟的到期时间。这是必要的,以便在会话结束时能够访问会话的值。会话本体在实际到期后五分钟被设置,以确保其被清理,但前提是我们会进行必要的处理。
这SessionRepository.findById(String)方法确保不会返回过期会话。这意味着你无需在使用会话前检查过期日期。 |
Spring Session 依赖于 Redis 的删除和过期密钥空间通知来触发SessionDeletedEvent以及一个SessionExpiredEvent分别。SessionDeletedEvent或SessionExpiredEvent确保与会期被清理。例如,当你使用 Spring Session 的 WebSocket 支持时,Redis 过期或删除事件会触发与会话相关的任何 WebSocket 连接被关闭。
过期时间不会直接在会话密钥上追踪,因为这意味着会话数据将不再可用。相反,使用特殊的会话过期密钥。在上述示例中,过期密钥如下:
APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe "" EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
当会话的密钥被删除或过期时,密钥空间通知会触发对实际会话的查找,并且SessionDestroyedEvent被解雇了。
仅依赖 Redis 过期的一个问题是,如果密钥未被访问,Redis 无法保证事件过期的时间。 具体来说,Redis 用于清理过期密钥的后台任务是低优先级任务,可能不会触发密钥过期。 更多细节请参见 Redis 文档中的“事件过期时间”部分。
为了避免事件过期不一定发生,我们可以确保每个密钥在预期到期时被访问。 这意味着,如果密钥的TTL已过期,Redis会移除密钥并在我们尝试访问密钥时触发过期事件。
因此,每个会话的到期时间也会被追踪到最接近的分钟。 这使得后台任务能够访问可能已过期的会话,确保 Redis 过期事件以更确定性的方式触发。 以下示例展示了这些事件:
SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe EXPIRE spring:session:expirations1439245080000 2100
后台任务随后利用这些映射显式请求每个键。 通过访问密钥而非删除密钥,我们确保 Redis 只有在 TTL 过期时才会为我们删除密钥。
| 我们不会明确删除密钥,因为在某些情况下,可能存在竞态条件错误地将密钥标记为过期,而实际上并非如此。 除非使用分布式锁(否则会损害性能),否则无法确保过期映射的一致性。 通过访问密钥,我们确保只有在该密钥的TTL过期时才会移除密钥。 |
SessionDeletedEvent和SessionExpiredEvent
SessionDeletedEvent和SessionExpiredEvent都是SessionDestroyedEvent.
RedisIndexedSessionRepository支撑发射A。SessionDeletedEvent当 a会期被删除或SessionExpiredEvent当 a会期到期。
这是确保与会期被妥善清理。
例如,当与WebSockets集成时,SessionDestroyedEvent负责关闭所有活跃的WebSocket连接。
开火SessionDeletedEvent或SessionExpiredEvent通过SessionMessageListener(会话信息听听器)该系统监听 Redis Keyspace 事件。
为了实现这一点,需要启用用于通用命令和过期事件的 Redis Keyspace 事件。
以下示例展示了如何实现:
redis-cli config set notify-keyspace-events Egx
如果你使用,@EnableRedisHttpSession(enableIndexingAndEvents = true),管理SessionMessageListener(会话信息听听器)并且启用必要的 Redis Keyspace 事件是自动完成的。
然而,在安全的 Redis 环境中,配置命令是被禁用的。
这意味着 Spring Session 无法为你配置 Redis Keyspace 事件。
要禁用自动配置,请添加ConfigureRedisAction.NO_OP像豆子一样。
例如,使用 Java 配置时,可以使用以下功能:
@Bean
ConfigureRedisAction configureRedisAction() {
return ConfigureRedisAction.NO_OP;
}
在XML配置中,您可以使用以下内容:
<util:constant
static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
用SessionCreatedEvent
当会话创建时,会向 Redis 发送一个事件,信道编号为Spring:session:channel:created:33fdd1b6-b496-4b33-9f7d-df96679d32fe,
哪里33FDD1B6-B496-4B33-9F7D-DF96679D32Fe是会话ID。活动的正体是创建的会议。
如果注册为消息监听器(默认),RedisIndexedSessionRepository然后将Redis消息翻译成SessionCreatedEvent.
在Redis中查看会话
安装 redis-cli 后,你可以用 redis-cli 检查 Redis 中的数值。 例如,你可以在终端中输入以下信息:
$ redis-cli
redis 127.0.0.1:6379> keys *
1) "spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021" (1)
2) "spring:session:expirations:1418772300000" (2)
| 1 | 该密钥的后缀是春季会话的会话标识符。 |
| 2 | 该密钥包含当时应删除的所有会话ID1418772300000. |
你还可以查看每次会话的属性。 以下示例展示了如何实现:
redis 127.0.0.1:6379> hkeys spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021
1) "lastAccessedTime"
2) "creationTime"
3) "maxInactiveInterval"
4) "sessionAttr:username"
redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021 sessionAttr:username
"\xac\xed\x00\x05t\x00\x03rob"
用ReactiveRedisSessionRepository
ReactiveRedisSessionRepository是ReactiveSessionRepository该系统通过使用 Spring Data 实现响应式RedisOperations(响应式RedisOperations).
在网络环境中,这通常与以下结合使用。网络会话商店.
实例化ReactiveRedisSessionRepository
以下示例展示了如何创建新实例:
// ... create and configure connectionFactory and serializationContext ...
ReactiveRedisTemplate<String, Object> redisTemplate = new ReactiveRedisTemplate<>(connectionFactory,
serializationContext);
ReactiveSessionRepository<? extends Session> repository = new ReactiveRedisSessionRepository(redisTemplate);
关于如何创建ReactiveRedisConnectionFactory,参见Spring Data Redis参考文献。
用@EnableRedisWebSession
在网络环境中,创建新文件的最简单方式ReactiveRedisSessionRepository是 使用@EnableRedisWebSession.
您可以使用以下属性来自定义配置:
-
maxInactiveIntervalInSeconds:会话结束前的时间,以秒为单位
-
redisNamespace:允许为会话配置应用特定的命名空间。Redis 密钥和通道 ID 以 q 前缀 开头
<redisNamespace>:. -
flushMode:允许指定何时将数据写入 Redis。默认只有当
救被调用于ReactiveSessionRepository. 一个值为冲洗模式。立即尽快写信给Redis。
在Redis中查看会话
安装 redis-cli 后,你可以用 redis-cli 检查 Redis 中的数值。 例如,你可以在终端窗口中输入以下命令:
$ redis-cli
redis 127.0.0.1:6379> keys *
1) "spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021" (1)
| 1 | 该密钥的后缀是春季会话的会话标识符。 |
你也可以通过使用赫基斯命令。
以下示例展示了如何实现:
redis 127.0.0.1:6379> hkeys spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021
1) "lastAccessedTime"
2) "creationTime"
3) "maxInactiveInterval"
4) "sessionAttr:username"
redis 127.0.0.1:6379> hget spring:session:sessions:4fc39ce3-63b3-4e17-b1c4-5e1ed96fb021 sessionAttr:username
"\xac\xed\x00\x05t\x00\x03rob"
用地图会话仓库
这地图会话仓库允许持久化会期在地图,其中密钥为会期ID 和值为会期.
你可以用并发哈希图作为一种测试或便利机制。
或者,你也可以用分布式地图实现。例如,它可以与Hazelcast一起使用。
实例化地图会话仓库
以下示例展示了如何创建新实例:
SessionRepository<? extends Session> repository = new MapSessionRepository(new ConcurrentHashMap<>());
使用 Spring Session 和 Hazlecast
Hazelcast示例是一个完整的应用程序,展示了如何使用Hazelcast的春季会话。
运行时,请使用以下命令:
./gradlew :samples:hazelcast:tomcatRun
Hazelcast Spring 示例是一个完整的应用程序,演示如何使用 Hazelcast 和 Spring Security 的 Spring Session。
其中包含了Hazelcast的示例地图聆听器支持发射的实现SessionCreatedEvent,SessionDeletedEvent和SessionExpiredEvent.
运行时,请使用以下命令:
./gradlew :samples:hazelcast-spring:tomcatRun
用ReactiveMapSessionRepository
这ReactiveMapSessionRepository允许持久化会期在地图,其中密钥为会期ID 和值为会期.
你可以用并发哈希图作为一种测试或便利机制。
或者,你也可以用分布式地图实现,要求提供的地图一定是非阻塞。
用JdbcIndexedSessionRepository
JdbcIndexedSessionRepository是会话仓库实现中使用 Spring 的Jdbc运营用于将会话存储在关系数据库中。
在网络环境中,这通常与以下结合使用。SessionRepositoryFilter.
请注意,该实现不支持发布会话事件。
实例化JdbcIndexedSessionRepository
以下示例展示了如何创建新实例:
JdbcTemplate jdbcTemplate = new JdbcTemplate();
// ... configure jdbcTemplate ...
TransactionTemplate transactionTemplate = new TransactionTemplate();
// ... configure transactionTemplate ...
SessionRepository<? extends Session> repository = new JdbcIndexedSessionRepository(jdbcTemplate,
transactionTemplate);
关于如何创建和配置的更多信息Jdbc模板和PlatformTransactionManager,参见Spring框架参考文档。
用@EnableJdbcHttpSession
在网络环境中,创建新文件的最简单方式JdbcIndexedSessionRepository是 使用@EnableJdbcHttpSession.
你可以在示例和指南中找到完整的示例使用示例(从这里开始)。你可以使用以下属性来自定义配置:
-
tableName:Spring Session 用于存储会话的数据库表名称
-
maxInactiveIntervalInSeconds:会话结束前的时间(秒数)
存储详情
默认情况下,该实现使用SPRING_SESSION和SPRING_SESSION_ATTRIBUTES用来存储会话的表格。
请注意,你可以自定义桌面名称,如前所述。在这种情况下,用于存储属性的表名称是用提供的表名命名,后缀为_属性.
如果需要进一步定制,你可以通过以下方式自定义仓库使用的SQL查询set*查询二传方法。在这种情况下,你需要手动配置sessionRepository豆。
由于不同数据库厂商之间的差异,尤其是在存储二进制数据方面,务必使用针对你数据库的SQL脚本。大多数主流数据库厂商的脚本都打包为org/springframework/session/jdbc/schema-*.sql,其中是目标数据库类型。*
例如,使用 PostgreSQL 时,您可以使用以下模式脚本:
CREATE TABLE SPRING_SESSION (
PRIMARY_ID CHAR(36) NOT NULL,
SESSION_ID CHAR(36) NOT NULL,
CREATION_TIME BIGINT NOT NULL,
LAST_ACCESS_TIME BIGINT NOT NULL,
MAX_INACTIVE_INTERVAL INT NOT NULL,
EXPIRY_TIME BIGINT NOT NULL,
PRINCIPAL_NAME VARCHAR(100),
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
);
CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
SESSION_PRIMARY_ID CHAR(36) NOT NULL,
ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
ATTRIBUTE_BYTES BYTEA NOT NULL,
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);
使用MySQL数据库时,您可以使用以下脚本:
CREATE TABLE SPRING_SESSION (
PRIMARY_ID CHAR(36) NOT NULL,
SESSION_ID CHAR(36) NOT NULL,
CREATION_TIME BIGINT NOT NULL,
LAST_ACCESS_TIME BIGINT NOT NULL,
MAX_INACTIVE_INTERVAL INT NOT NULL,
EXPIRY_TIME BIGINT NOT NULL,
PRINCIPAL_NAME VARCHAR(100),
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
SESSION_PRIMARY_ID CHAR(36) NOT NULL,
ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
ATTRIBUTE_BYTES BLOB NOT NULL,
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
用HazelcastIndexedSessionRepository
HazelcastIndexedSessionRepository是会话仓库实现了在Hazelcast分布式中存储会话的过程IMap.
在网络环境中,这通常与以下结合使用。SessionRepositoryFilter.
实例化HazelcastIndexedSessionRepository
以下示例展示了如何创建新实例:
Config config = new Config();
// ... configure Hazelcast ...
HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(config);
HazelcastIndexedSessionRepository repository = new HazelcastIndexedSessionRepository(hazelcastInstance);
有关如何创建和配置Hazelcast实例的更多信息,请参见Hazelcast文档。
用@EnableHazelcastHttpSession
使用 Hazelcast 作为你的会话仓库,你可以添加@EnableHazelcastHttpSession注释到@Configuration类。
这样做可以扩展@EnableSpringHttpSession注释,但使会话仓库为你提供Hazelcast。
你必须提供一份Hazelcast实例需要豆子才能让配置正常工作。
你可以在示例和指南(从这里开始)中找到完整的配置示例。
基础定制
你可以在@EnableHazelcastHttpSession自定义配置:
-
maxInactiveIntervalInSeconds:会话结束前的时间,以秒为单位。默认时间为1800秒(30分钟)
-
sessionMapName:分布式的名称
地图Hazelcast 中用于存储会话数据。
会议活动
使用地图聆听器回应被添加、驱逐和从分发版中移除的条目地图导致这些事件触发发布SessionCreatedEvent,SessionExpiredEvent和SessionDeletedEvent分别通过应用事件发布者.
存储详情
会话存储在分布式中IMap在Hazelcast中。
这IMap接口方法用于get()和put()会话。
此外,值()方法支持一个查找ByIndexNameSessionRepository#findByIndexNameAndIndexValue运算,结合适当的价值提取器(需要在Hazelcast注册)。有关该配置的更多信息,请参见Hazelcast Spring样本。
会话的到期IMap由Hazelcast支持,在条目上设置时间以存活时间处理put()进入IMap.闲置时间超过寿命的条目(会话)会自动从IMap.
你不需要配置任何设置,比如最大空闲秒或存活秒对于IMap在Hazelcast配置中。
注意如果你用的是Hazelcast的地图商店坚持你的会话IMap,在从中重新加载会话时,以下限制适用地图商店:
-
装填扳机
EntryAddedListener结果如下SessionCreatedEvent重新出版 -
重新加载时段使用默认TTL。
IMap结果是会话失去了原本的TTL
用CookieSerializer
一个CookieSerializer负责定义会话 Cookie 的编写方式。
Spring Session 默认实现方式为默认Cookie序列化器.
暴露CookieSerializer作为豆子
揭露CookieSerializer因为 Spring Bean 在使用以下配置时对现有配置进行了补充@EnableRedisHttpSession.
以下示例展示了如何实现:
@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID"); (1)
serializer.setCookiePath("/"); (2)
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$"); (3)
return serializer;
}
| 1 | 我们会自定义 Cookie 的名称为JSESSIONID. |
| 2 | 我们会自定义 cookie 的路径(而不是上下文根的默认路径)。/ |
| 3 | 我们将域名模式(正则表达式)自定义为^.? \\. (\\w\\。[A-Z]+)$. 这允许跨域和应用共享会话。如果正则表达式不匹配,则不设置域,使用现有域。如果正则表达式匹配,则使用第一个分组作为域。这意味着请求 child.example.com 将域设置为example.com. 然而,向localhost:8080/或192.168.1.100:8080/请求时,cookie未被设置,因此在开发中仍然可运行,生产过程中无需更改。 |
| 你应仅在有效的域字符上匹配,因为域名会反映在响应中。这样做可以防止恶意用户实施如HTTP响应分拆等攻击。 |
定制CookieSerializer
您可以通过以下任一配置选项自定义会话 cookie 的编写方式,默认Cookie序列化器.
-
cookieName:用来用的饼干名称。 违约:会期. -
使用SecureCookie: 指定是否应使用安全Cookie。默认:使用值HttpServletRequest.isSecure()在创造时期。 -
cookiePath(cookie路径):cookie的路径。默认:上下文根。 -
cookieMaxAge: 指定会话创建时 cookie 的最大年龄。 违约:-1,这表示浏览器关闭时应移除该 cookie。 -
jvm路线: 指定一个后缀要附加在会话 ID 后并包含在 Cookie 中。用于识别应路由哪个 JVM 以实现会话亲和性。在某些实现(如 Redis 中),该选项不带来性能提升。但它可以帮助追踪特定用户的日志。 -
域名: 允许指定用于 cookie 的特定域名。该选项易于理解,但通常需要开发环境和生产环境之间的不同配置。 看域名模式作为替代方案。 -
域名模式:用于从中提取域名的大小写不区分模式HttpServletRequest#getServerName(). 该模式应提供单一分组,用于提取 cookie 域的值。如果正则表达式不匹配,则不设置域,使用现有域。如果正则表达式匹配,则使用第一个分组作为域。 -
同址:同站cookie 指令。以禁用序列化同站Cookie 指令,你可以将此值设置为零. 违约:宽松
| 你应仅在有效的域字符上匹配,因为域名会反映在响应中。这样做可以防止恶意用户实施如HTTP响应分拆等攻击。 |
定制会话仓库
实现自定义会话仓库API应该是个相当简单的任务。
将自定义实现与@EnableSpringHttpSession支持允许你重用现有的春季会话配置设施和基础设施。
不过,有几个方面值得更深入地考虑。
在HTTP请求的生命周期内,HttpSession通常被持久化为会话仓库两次。
第一个持久作是确保一旦客户端访问会话 ID,会话即可访问,且在会话提交后写入,因为可能会对会话进行进一步修改。
考虑到这一点,我们通常建议会话仓库实施 跟踪变更,确保只有 delta 被保存。
这在高度并发的环境中尤为重要,因为多个请求同时运行在同一个平台上HttpSession因此,会引发竞赛条件,请求会覆盖对方对会话属性的更改。
所有会话仓库Spring Session 提供的实现采用上述方法来持久化会话变更,并在实现自定义时提供指导会话仓库.
注意,实现自定义时也适用同样的建议ReactiveSessionRepository也。
在这种情况下,你应该使用@EnableSpringWebSession.