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

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。 https://blog.csdn.net/u010870518/article/details/57406162

前言

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

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

在之前寫的一篇文章中:html5

使用Redis存儲Nginx+Tomcat負載均衡集羣的Session:http://blog.csdn.net/xlgen157387/article/details/52024139java

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

這裏寫圖片描述

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

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

不過使用過tomcat-redis-session-manager 的都應該知道,配置相對仍是有一點繁瑣的,須要人爲的去修改Tomcat的配置,須要耦合Tomcat等Servlet容器的代碼,而且對於分佈式Redis集羣的管理並非很好,與之相對的我的認爲比較好的一個框架Spring Session能夠真正對用戶透明的去管理分佈式Session。redis

Spring Session不依賴於Servlet容器,而是Web應用代碼層面的實現,直接在已有項目基礎上加入spring Session框架來實現Session統一存儲在Redis中。若是你的Web應用是基於Spring框架開發的,只須要對現有項目進行少許配置,便可將一個單機版的Web應用改成一個分佈式應用,因爲不基於Servlet容器,因此能夠隨意將項目移植到其餘容器。算法

Spring Session使用

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

官方文檔地址: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共享的問題。

1、特性

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。

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

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

這裏寫圖片描述

項目展現:

這裏寫圖片描述

(1)基本環境需求

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

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

<dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>1.3.0.RELEASE</version> <type>pom</type> </dependency> <dependency> <groupId>biz.paluch.redis</groupId> <artifactId>lettuce</artifactId> <version>3.5.0.Final</version> </dependency>

(3)添加Spring配置文件

添加了必要的依賴以後,咱們須要建立相應的Spring配置。Spring配置是要建立一個Servlet過濾器,它用Spring Session支持的HttpSession實現來替換容器自己HttpSession實現。這一步也是Spring Session的核心。

<context:annotation-config/> <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/> <bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>

 

上述代碼註釋:

這裏寫圖片描述

LettuceConnectionFactory實例是配置Redis的ConnectionFactory。

注意:

<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
  • 1

查看源代碼能夠看到,默認的Redis連接配置爲:

這裏寫圖片描述

所以,若是有本身的Redis配置,請修改,例以下邊的配置:

<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"> <property name="hostName" value="192.168.1.149"/> <property name="port" value="6379"/> <property name="password" value="123456"/> </bean>

 

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

添加以下配置讓Spring Session再也不執行config命令

<util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>
  • 1

若是不添加的話,會報以下錯誤:

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

(5)在web.xml中添加DelegatingFilterProxy

<filter> <filter-name>springSessionRepositoryFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSessionRepositoryFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping>

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

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

@Controller
@RequestMapping(value = "/spring/session", produces = {ConstString.APP_JSON_UTF_8}) public class SpringSessionDemoController { @RequestMapping(value = "/setSession.do", method = RequestMethod.GET) public void setSession(HttpServletRequest request, HttpServletResponse response) { String name = request.getParameter("name"); String value = request.getParameter("value"); request.getSession().setAttribute(name, value); } @RequestMapping(value = "/getSession.do", method = RequestMethod.GET) public void getInterestPro(HttpServletRequest request, HttpServletResponse response) { String name = request.getParameter("name"); System.out.println("------" + request.getSession().getAttribute(name)); } @RequestMapping(value = "/removeSession.do", method = RequestMethod.GET) public void removeSession(HttpServletRequest request, HttpServletResponse response) { String name = request.getParameter("name"); request.getSession().removeAttribute(name); } }

 

這裏寫圖片描述

(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,這一點是相當重要的!


下一篇:

Spring Session解決分佈式Session問題的實現原理:http://blog.csdn.net/xlgen157387/article/details/60321984


參考文章:

一、http://blog.csdn.net/xiao__gui/article/details/52706243

相關文章
相關標籤/搜索