Spring Session - WebSocket
HttpSession Setup
第一步是将 Spring Session 与 HttpSession 集成。这些步骤已在 HttpSession with Redis Guide 中概述。
确保在继续之前,您已将 Spring 会话与 HttpSession 集成。
Spring Configuration
在典型的 Spring WebSocket 应用程序中,您会实现 WebSocketMessageBrokerConfigurer
。例如,配置可能类似于以下内容:
/*
* 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.websocket;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* @author Rob Winch
*/
// tag::class[]
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/messages").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue/", "/topic/");
registry.setApplicationDestinationPrefixes("/app");
}
}
// end::class[]
我们可以更新配置以使用 Spring 会话的 WebSocket 支持。以下示例演示如何操作:
Unresolved include directive in modules/ROOT/pages/guides/boot-websocket.adoc - include::example$spring-session-samples/spring-session-sample-boot-websocket/src/main/java/sample/config/WebSocketConfig.java[]
连接到 Spring 会话支持时,我们只需做两件事:
1 | 不实现 WebSocketMessageBrokerConfigurer ,而是扩展 AbstractSessionWebSocketMessageBrokerConfigurer |
2 | 将 registerStompEndpoints 方法重命名为 configureStompEndpoints |
`AbstractSessionWebSocketMessageBrokerConfigurer`在幕后执行什么操作?
-
将
WebSocketConnectHandlerDecoratorFactory
作为一个WebSocketHandlerDecoratorFactory
添加到WebSocketTransportRegistration
。这将确保会触发一个包含SessionConnectEvent
的自定义SessionConnectEvent
。在 Spring Session 结束时,WebSocketSession
对于结束任何仍然处于打开状态的 WebSocket 连接是必需的。 -
将
SessionRepositoryMessageInterceptor
作为一个HandshakeInterceptor
添加到每个StompWebSocketEndpointRegistration
。这将确保会将Session
添加到 WebSocket 属性,以更新最新的访问时间。 -
将
SessionRepositoryMessageInterceptor
作为一个ChannelInterceptor
添加到我们的入站ChannelRegistration
。这将确保我们每收到一条入站消息就会更新 Spring Session 的上次访问时间。 -
将
WebSocketRegistryListener
创建为一个 Spring bean。这将确保我们拥有所有Session
ID 到相应 WebSocket 连接的映射。通过维护此映射,我们可以再 Spring Session(HttpSession) 结束时关闭所有 WebSocket 连接。
websocket
Sample Application
`websocket`示例应用程序演示了如何在 WebSocket 中使用 Spring Session。
Running the websocket
Sample Application
您可以获取 源代码 并调用以下命令运行示例:
$ ./gradlew :spring-session-sample-boot-websocket:bootRun
出于测试会话到期时间的目的,你可能希望在启动应用程序之前添加以下配置属性,将会话到期时间更改为 1 分钟(默认值为 30 分钟): |
server.servlet.session.timeout=1m # Session timeout. If a duration suffix is not specified, seconds will be used.
要让示例发挥作用,你必须在 localhost 上 install Redis 2.8+ 并使用默认端口 (6379) 运行它。或者,你可以更新 |
您现在应该能够访问 [role="bare"][role="bare"]http://localhost:8080/ 中的应用程序。
Exploring the websocket
Sample Application
现在你可以尝试使用该应用程序。使用以下信息进行身份验证:
-
Username rob
-
Password password
现在,单击*Login*按钮。你现在应该以用户*rob*的身份进行身份验证。
打开一个隐身窗口并访问 [role="bare"][role="bare"]http://localhost:8080/
系统会提示你提供一个登录表单。使用以下信息进行身份验证:
-
Username luke
-
Password password
现在从 Rob 发送一条消息给 Luke。消息应该会显示出来。
等待两分钟,然后再次尝试从 Rob 给 Luke 发送一条消息。你可以看到,消息不再发送。
Why two minutes?
Spring Session 在 60 秒后到期,但不能保证在 60 秒内收到来自 Redis 的通知。为了确保在合理的时间范围内关闭套接字,Spring Session 会在每分钟的第 00 秒运行一个后台任务,以强制清除所有过期的会话。这意味着你需要最多等待两分钟,WebSocket 连接才会关闭。 |
现在,您可以尝试访问 [role="bare"][role="bare"]http://localhost:8080/,您会收到再次进行身份验证的提示。这表明会话已正确过期。
现在重复相同的练习,但是不要等待两分钟,而是在每 30 秒内从每个用户发送一条消息。您可以看到仍会继续发送消息。尝试访问 [role="bare"][role="bare"]http://localhost:8080/,您不会收到再次进行身份验证的提示。这表明会话保持活跃。
只有来自用户的消息才能使会话保持活动状态。这是因为只有来自用户的消息才表示用户活动。收到的消息并不表示活动,因此不会续订会话过期。 |