该版本仍在开发中,尚未被视为稳定。最新稳定版请使用Spring Session 3.5.3spring-doc.cadn.net.cn

春季会话 - WebSocket

本指南介绍了如何使用 Spring Session 确保 WebSocket 消息保持你的 HttpSession 活跃。spring-doc.cadn.net.cn

Spring Session 的 WebSocket 支持仅与 Spring 的 WebSocket 支持兼容。具体来说,它无法直接使用 JSR-356,因为 JSR-356 没有拦截 WebSocket 消息的机制。

HttpSession 设置

第一步是将春季会话与HttpSession集成。这些步骤已经在《HttpSession with Redis指南》中列出。spring-doc.cadn.net.cn

请确保你已经将春季会话与HttpSession集成后再继续。spring-doc.cadn.net.cn

Spring配置

在典型的 Spring WebSocket 应用中,你会实现WebSocketMessageBrokerConfigurer. 例如,配置可能如下:spring-doc.cadn.net.cn

@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");
	}

}

我们可以更新配置以使用Spring Session的WebSocket支持。以下示例展示了如何实现:spring-doc.cadn.net.cn

src/main/java/samples/config/WebSocketConfig.java
@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<Session> { (1)

	@Override
	protected void configureStompEndpoints(StompEndpointRegistry registry) { (2)
		registry.addEndpoint("/messages").withSockJS();
	}

	@Override
	public void configureMessageBroker(MessageBrokerRegistry registry) {
		registry.enableSimpleBroker("/queue/", "/topic/");
		registry.setApplicationDestinationPrefixes("/app");
	}

}

要连接春季课程的支持,我们只需要改变两点:spring-doc.cadn.net.cn

1 而不是实现WebSocketMessageBrokerConfigurer,我们延展AbstractSessionWebSocketMessageBrokerConfigurer
2 我们会重新命名registerStompEndpoints方法configureStompEndpoints

什么会AbstractSessionWebSocketMessageBrokerConfigurer幕后工作?spring-doc.cadn.net.cn

  • WebSocketConnectHandlerDecoratorFactory作为WebSocketHandlerDecoratorFactoryWebSocketTransportRegistration. 这确保了习惯会话连接事件是包含WebSocketSession. 这WebSocketSession是结束任何在春季会话结束时仍然开放的WebSocket连接所必需的。spring-doc.cadn.net.cn

  • 会话存储器MessageInterceptor作为握手拦截者每一个StompWebSocketEndpointRegistration. 这确保了会期被添加到WebSocket属性中,以便更新最后访问时间。spring-doc.cadn.net.cn

  • 会话存储器MessageInterceptor作为通道拦截者前往我们的入境频道注册. 这确保每次收到入站消息时,我们Spring Session的最后访问时间都会被更新。spring-doc.cadn.net.cn

  • WebSocketRegistryListener作为春豆创建。这确保了我们对所有会期ID,指向对应的WebSocket连接。通过保持这种映射,我们可以在Spring Session(HttpSession)结束时关闭所有WebSocket连接。spring-doc.cadn.net.cn

Websocket示例应用

Websocket示例应用演示如何使用 WebSockets 的 Spring Session。spring-doc.cadn.net.cn

运行Websocket示例应用

您可以通过获取源代码并调用以下命令来运行示例:spring-doc.cadn.net.cn

$ ./gradlew :spring-session-sample-boot-websocket:bootRun

为了测试会话到期,你可能需要在启动应用程序前添加以下配置属性,将会话到期时间改为1分钟(默认为30分钟):spring-doc.cadn.net.cn

src/main/resources/application.properties
server.servlet.session.timeout=1m # Session timeout. If a duration suffix is not specified, seconds will be used.
为了让样本正常工作,你必须在localhost上安装Redis 2.8+,并用默认端口(6379)运行。 或者,你也可以更新RedisConnection工厂指向一个Redis服务器。 另一个选择是用 Docker 在 localhost 上运行 Redis。 详见 Docker Redis 仓库中的详细说明。

你现在应该可以在localhost:8080/访问该应用了spring-doc.cadn.net.cn

探索Websocket示例应用

现在你可以尝试使用该应用程序。请用以下信息进行身份验证:spring-doc.cadn.net.cn

现在点击登录按钮。你现在应该被认证为用户盗窃者。spring-doc.cadn.net.cn

打开一个无痕窗口访问 localhost:8080/spring-doc.cadn.net.cn

系统会提示您填写登录表单。请用以下信息进行身份验证:spring-doc.cadn.net.cn

现在,把罗布的消息发给卢克。消息应该会出现。spring-doc.cadn.net.cn

等两分钟,再试着从Rob给Luke发消息。你可以看到消息已经不再发送了。spring-doc.cadn.net.cn

为什么是两分钟?

Spring Session 在 60 秒后到期,但 Redis 的通知并不保证在 60 秒内出现。为了确保套接字在合理时间内关闭,Spring Session 每分钟在 00 秒执行一次后台任务,强制清理所有过期的会话。这意味着你最多需要等待两分钟,WebSocket 连接就会关闭。spring-doc.cadn.net.cn

你现在可以尝试访问localhost:8080/,提示再次验证。这表明会话已经正常到期。spring-doc.cadn.net.cn

现在重复同样的练习,但不要等两分钟,而是每30秒从每个用户发送一条消息。你可以看到消息还在继续发送。尝试访问localhost:8080/你不会再次被提示认证。这表明会话仍然保持活跃。spring-doc.cadn.net.cn

只有用户发送的消息才能保持会话存活。这是因为只有来自用户的消息才暗示用户活动。收到的消息并不意味着活动,因此不会续订会话的到期。