Spring Session - WebSocket
HttpSession 設定
第一步是將 Spring Session 與 HttpSession 整合。這些步驟已在使用 Redis 的 HttpSession 指南中概述。
請確保在繼續之前已將 Spring Session 與 HttpSession 整合。
Spring 配置
在典型的 Spring WebSocket 應用中,您會實現 WebSocketMessageBrokerConfigurer
。例如,配置可能如下所示
@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 支援。以下示例展示瞭如何實現
@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 Session 支援,我們只需更改兩件事
1 | 我們擴充套件 AbstractSessionWebSocketMessageBrokerConfigurer ,而不是實現 WebSocketMessageBrokerConfigurer |
2 | 我們將 registerStompEndpoints 方法重新命名為 configureStompEndpoints |
AbstractSessionWebSocketMessageBrokerConfigurer
在幕後做了什麼?
-
WebSocketConnectHandlerDecoratorFactory
作為WebSocketHandlerDecoratorFactory
新增到WebSocketTransportRegistration
。這確保觸發一個包含WebSocketSession
的自定義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
示例應用
websocket
示例應用演示瞭如何將 Spring Session 與 WebSockets 一起使用。
執行 websocket
示例應用
您可以透過獲取原始碼並執行以下命令來執行示例
$ ./gradlew :spring-session-sample-boot-websocket:bootRun
為了測試會話過期,您可以在啟動應用之前新增以下配置屬性,將會話過期時間改為 1 分鐘(預設為 30 分鐘) 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) 執行它。或者,您可以更新 RedisConnectionFactory 以指向 Redis 伺服器。另一種選擇是使用Docker 在 localhost 上執行 Redis。有關詳細說明,請參閱Docker Redis 倉庫。 |
現在您應該能夠透過 localhost:8080/ 訪問該應用
探索 websocket
示例應用
現在您可以嘗試使用該應用。使用以下資訊進行身份驗證
-
使用者名稱 rob
-
密碼 password
現在點選登入按鈕。您現在應該已以使用者 rob 的身份透過身份驗證。
開啟隱身視窗並訪問 localhost:8080/
系統會提示您填寫登入表單。使用以下資訊進行身份驗證
-
使用者名稱 luke
-
密碼 password
現在從 rob 傳送訊息給 luke。訊息應該會顯示。
等待兩分鐘,然後再次嘗試從 rob 傳送訊息給 luke。您會看到訊息不再發送。
為什麼是兩分鐘?
Spring Session 在 60 秒內過期,但無法保證在 60 秒內收到 Redis 的通知。為了確保套接字在合理的時間內關閉,Spring Session 每分鐘的 00 秒會執行一個後臺任務,強制清理所有過期的會話。這意味著您最多需要等待兩分鐘,WebSocket 連線才會關閉。 |
您現在可以嘗試訪問 localhost:8080/。系統會再次提示您進行身份驗證。這表明會話已正常過期。
現在重複相同的練習,但不是等待兩分鐘,而是每隔 30 秒從每個使用者傳送一條訊息。您會看到訊息持續傳送。嘗試訪問 localhost:8080/。系統不會再次提示您進行身份驗證。這表明會話保持活動狀態。
只有使用者傳送的訊息才能保持會話活動。這是因為只有來自使用者的訊息才表示使用者活動。接收到的訊息不表示活動,因此不會更新會話過期時間。 |