鵬哥之前也沒有Spring Session的基礎,完全是從零開始,在搜索了無數教程和一步一步的跟蹤代碼之後,慢慢摸清了一些門道,分享給大家。知識點很多很雜,思路和流程主要參考一網友懷瑾握瑜的博客(https://www.cnblogs.com/lxyit/category/1303872.html),因為作者的思路還算清晰,鵬哥受益匪淺。
先來看下Session事件抽象UML類圖,整體掌握事件之間的依賴關係。

Session Event最頂層是ApplicationEvent,即Spring上下文事件對象。由此可以看出Spring-Session的事件機制是基於Spring上下文事件實現。
抽象的AbstractSessionEvent事件對象提供了獲取Session(這裡的是指Spring Session的對象)和SessionId。
基於事件的類型,分類為:
- Session創建事件
- Session刪除事件
- Session過期事件
事件對象只是對事件本身的抽象,描述事件的屬性,如:
- 獲取事件產生的源:getSource獲取事件產生源
- 獲取相應事件特性:getSession/getSessoinId獲取時間關聯的Session
事件的觸發機制

- ApplicationEventPublisher實現用於發佈Spring上下文事件ApplicationEvent
- ApplicationListener實現用於監聽Spring上下文事件ApplicationEvent
- ApplicationEvent抽象上下文事件
Session事件的流程實現如下:

上圖展示了Spring-Session事件流程圖,事件源來自於Redis鍵空間通知,在spring-data-redis項目中抽象MessageListener監聽Redis事件源,然後將其傳播至spring應用上下文發佈者,由發佈者發佈事件。在spring上下文中的監聽器Listener即可監聽到Session事件。
因為兩者是Spring框架提供的對Spring的ApplicationEvent的支持。Session Event基於ApplicationEvent實現,必然也有其相應發佈者和監聽器的的實現。
Spring-Session中的RedisSession的SessionRepository是RedisOperationSessionRepository。所有關於RedisSession的管理操作都是由其實現,所以Session的產生源是RedisOperationSessionRepository。
在RedisOperationSessionRepository中持有ApplicationEventPublisher對象用於發佈Session事件。
但是該ApplicationEventPublisher是空實現,實際實現是在應用啟動時由Spring-Session自動配置。在spring-session-data-redis模塊中RedisHttpSessionConfiguration中有關於創建RedisOperationSessionRepository Bean時將調用set方法將ApplicationEventPublisher配置。
以上部分探索了Session事件的發佈者和監聽者,但是核心事件的觸發發佈則是由Redis的鍵空間通知機制觸發,當有Session創建/刪除/過期時,Redis鍵空間會通知Spring-Session應用。
RedisOperationsSessionRepository實現spring-data-redis中的MessageListener接口。
該監聽器即用來監聽redis發佈的消息。RedisOperationsSessionRepositorys實現了該Redis鍵空間消息通知監聽器接口
Session創建事件的觸發

- 由RedisOperationSessionRepository向Redis指定通道
- {sessionId}發佈一個message
- MessageListener的實現RedisOperationSessionRepository監聽到Redis指定通道
- {sessionId}的消息
- 將其傳播至ApplicationEventPublisher
- ApplicationEventPublisher發佈SessionCreateEvent
- ApplicationListener監聽SessionCreateEvent,執行相應邏輯
Session刪除事件的觸發

- 由RedisOperationSessionRepository刪除Redis鍵空間中的指定Session的過期鍵,Redis鍵空間會向__keyevent *:del的channel發佈刪除事件消息
- MessageListener的實現RedisOperationSessionRepository監聽到Redis指定通道__keyevent *:del的消息
- 將其傳播至ApplicationEventPublisher
- ApplicationEventPublisher發佈SessionDeleteEvent
- ApplicationListener監聽SessionDeleteEvent,執行相應邏輯
Session失效事件的觸發
Session的過期事件流程比較特殊,因為Redis的鍵空間通知的特殊性,Redis鍵空間通知不能保證過期鍵的通知的及時性。

- RedisOperationsSessionRepository中有個定時任務方法每整分運行訪問整分Session過期鍵集合中的過期sessionId,如:spring:session:expirations:1439245080000。觸發Redis鍵空間會向__keyevent *:expired的channel發佈過期事件消息
- MessageListener的實現RedisOperationSessionRepository監聽到Redis指定通道__keyevent *:expired的消息
- 將其傳播至ApplicationEventPublisher
- ApplicationEventPublisher發佈SessionDeleteEvent
- ApplicationListener監聽SessionDeleteEvent,執行相應邏輯
總結
至此Spring-Session的Session事件通知模塊就已經很清晰:
- Redis鍵空間Session事件源:Session創建通道/Session刪除通道/Session過期通道
- Spring-Session中的RedisOperationsSessionRepository消息監聽器監聽Redis的事件類型
- RedisOperationsSessionRepository負責將其傳播至ApplicationEventPublisher
- ApplicationEventPublisher將其包裝成ApplicationEvent類型的Session Event發佈
- ApplicationListener監聽Session Event,處理相應邏輯
閱讀更多 程序猿鵬哥 的文章