170222、使用Spring Session和Redis解決分布式Session跨域共享問題


使用Spring Session和Redis解決分布式Session跨域共享問題

前言

對於分布式使用Nginx+Tomcat實現負載均衡,最常用的均衡算法有IP_Hash、輪訓、根據權重、隨機等。不管對於哪一種負載均衡算法,由於Nginx對不同的請求分發到某一個Tomcat,Tomcat在運行的時候分別是不同的容器里,因此會出現session不同步或者丟失的問題。

實際上實現Session共享的方案很多,其中一種常用的就是使用Tomcat、Jetty等服務器提供的Session共享功能,將Session的內容統一存儲在一個數據庫(如MySQL)或緩存(如Redis)中。

在以前寫的一篇文章中:

使用Redis存儲Nginx+Tomcat負載均衡集群的Session

這一篇文章中已經學習了一下,如何使用 tomcat-redis-session-manager 開源項目解決分布式session跨域的問題,他的主要思想是利用Servlet容器提供的插件功能,自定義HttpSession的創建和管理策略,並通過配置的方式替換掉默認的策略。tomcat-redis-session-manager重寫了Tomcat的org.apache.catalina.session.ManagerBase里邊的具體寫的操作, 將tomcat的session存儲位置指向了Redis:

RedisSessionManager繼承了org.apache.catalina.session.ManagerBase並重寫了add、findSession、createEmptySession、remove等方法,並將對session的增刪改查操作指向了對Redis數據存儲的操作。

有興趣可參考一篇Tomcat中session的管理機制:http://www.cnblogs.com/interdrp/p/4935614.html

不過使用過tomcat-redis-session-manager 的都應該知道,配置相對還是有一點繁瑣的,需要人為的去修改Tomcat的配置,需要耦合Tomcat等Servlet容器的代碼,並且對於分布式Redis集群的管理並不是很好,與之相對的個人認為比較好的一個框架spring Session可以真正對用戶透明的去管理分布式Session。

Spring Session不依賴於Servlet容器,而是Web應用代碼層面的實現,直接在已有項目基礎上加入spring Session框架來實現Session統一存儲在Redis中。如果你的Web應用是基於Spring框架開發的,只需要對現有項目進行少量配置,即可將一個單機版的Web應用改為一個分布式應用,由於不基於Servlet容器,所以可以隨意將項目移植到其他容器。

Spring Session使用

官方地址:http://projects.spring.io/spring-session/

官方文檔地址:http://docs.spring.io/spring-session/docs/1.3.0.RELEASE/reference/html5/

Spring Session提供了一套創建和管理Servlet HttpSession的方案。Spring Session提供了集群Session(Clustered Sessions)功能,默認采用外置的Redis來存儲Session數據,以此來解決Session共享的問題。

一、特性

Spring Session提供以下特性:

  1. API和用於管理用戶會話的實現;

  2. HttpSession - 允許以應用程序容器(即Tomcat)中性的方式替換HttpSession; 

    1. Clustered Sessions - Spring Session讓支持集群會話變得不那么繁瑣,並且不和應用程序容器金習性綁定到。

    2. Multiple Browser Sessions - Spring會話支持在單個瀏覽器實例中管理多個用戶的會話。

    3. RESTful APIs - Spring Session允許在headers 中提供會話ID以使用RESTful API。

 

二、基於XML配置方式的Spring Session案例實現

基於SSM框架的一個小案例,Git OS項目代碼地址:http://git.oschina.net/xuliugen/spring-session-demo

項目展示:

(1)基本環境需求

進行使用Spring Session的話,首先的是已經安裝好的有一個 Redis服務器!

(2)添加項目依賴(最基本的依賴使用)

(3)添加Spring配置文件

添加了必要的依賴之后,我們需要創建相應的Spring配置。Spring配置是要創建一個Servlet過濾器,它用Spring Session支持的HttpSession實現來替換容器本身HttpSession實現。這一步也是Spring Session的核心。

上述代碼注釋:

LettuceConnectionFactory實例是配置Redis的ConnectionFactory。

注意:

查看源代碼可以看到,默認的Redis鏈接配置為:

因此,如果有自己的Redis配置,請修改,例如下邊的配置:

(5)關於Error creating bean with name ‘enableRedisKeyspaceNotificationsInitializer’錯誤的處理:

添加如下配置讓Spring Session不再執行config命令:

如果不添加的話,會報如下錯誤:

Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name'enableRedisKeyspaceNotificationsInitializer' defined in classpath resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Invocation of initmethod failed; nested exception isjava.lang.IllegalStateException: Unable to configure Redis tokeyspace notifications. See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedeventCausedby: redis.clients.jedis.exceptions.JedisDataException: ERR unknown command config

 

(5)在web.xml中添加DelegatingFilterProxy

DelegatingFilterProxy將通過springSessionRepositoryFilter的名稱查找Bean並將其轉換為過濾器。對於調用DelegatingFilterProxy的每個請求,也將調用springSessionRepositoryFilter。

(6)Spring MVC controller代碼用於測試

(7)測試

訪問鏈接:http://localhost:8080/spring/session/setSession.do?name=xuiliugen&value=123456

使用工具查看Redis內容:

可以發現已經有值了!並且有expirations,可以看到箭頭指向的位置,是失效的時間記錄值!

(8)到此,Spring Session的使用已經完成!其他具體的細節請參考:http://git.oschina.net/xuliugen/spring-session-demo 項目源代碼。

總結

對於分布式環境Session跨域共享的問題,不管是使用開源的框架還是使用自己開發的框架,都需要明白的一個問題是:在Tomcat容器中創建Session是一個很耗費內存的事情。因此,我們在自己寫類似框架的時候,我們一定要注意的是,並不是Tomcat為我們創建好了Session之后,我們首先獲取Session然后再上傳到Redis等進行存儲,而是直接有我們自己創建Session,這一點是至關重要的!

注:其實可以使用token+redis就能解決,這邊博文只是提供一個思路!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM