使用Spring Session和Redis解决分布式Session跨域共享问题

原创 2017-02-27 徐刘根 Java后端技术

前言

对于分布式使用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就能解决,这边博文只是提供一个思路!

170222、使用Spring Session和Redis解决分布式Session跨域共享问题的更多相关文章

  1. 使用Spring Session和Redis解决分布式Session跨域共享问题

    http://blog.csdn.net/xlgen157387/article/details/57406162 使用Spring Session和Redis解决分布式Session跨域共享问题

  2. 使用SpringSession和Redis解决分布式Session共享问题

    SpringSession优势 遵循servlet规范,同样方式获取session,对应用代码无侵入且对于developers透明化 关键点在于做到透明和兼容 接口适配:仍然使用HttpServlet ...

  3. 通过jsonp解决浏览器的跨域共享

    因为浏览器的同源策略,普通ajax访问跨域请求返回的json数据是不会被浏览器接受的.看下面例子可以看出是访问不到的 首先 定义webapi 后台代码 public class JsopControl ...

  4. Spring Session解决分布式Session问题的实现原理

    使用Spring Session和Redis解决分布式Session跨域共享问题 上一篇介绍了如何使用spring Session和Redis解决分布式Session跨域共享问题,介绍了一个简单的案例 ...

  5. Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session框架

    Tornado 自定义session,与一致性哈希 ,基于redis 构建分布式 session import tornado.ioloop import tornado.web from myhas ...

  6. 跨域共享cookie和跨域共享session

    转载自:http://blog.csdn.net/ahhsxy/article/details/7356128 这里所说的跨域,是指跨二级域名,而且这些域名对应的应用都在同一个app上, 比如我有以下 ...

  7. session跨域共享问题解决方案

    在讨论 session 跨域共享问题之前,我们首先要了解 session 做了什么,没做什么 1.HTTP是无状态的,也就是说服务器不知道谁访问过他,但是有时间,又需要我们去保留这个状态比如说用户的登 ...

  8. session跨域共享解决方案

    要让session跨域共享,需要解决三个问题: 1.通过什么方法来传递session_id? 2.通过什么方法来保存session信息? 3.通过什么方法来进行跨域? 一.传递session_id有4 ...

  9. C#彻底解决Web Browser 跨域读取Iframes内容

    C#彻底解决Web Browser 跨域读取Iframes内容 用C# winform的控件web browser 读取网页内容,分析一下数据,做一些采集工作. 如果是同一个域名下面还是好办的,基本上 ...

随机推荐

  1. 【转】C# 视频监控系列(13):H264播放器——控制播放和截图

    本文原文地址:http://www.cnblogs.com/over140/archive/2009/03/30/1421531.html 阿里云栖社区也有相关的视频开发案例:https://yq.a ...

  2. layer弹窗的操作方法

    1.首先去http://layer.layui.com/下载插件 2.在网站上有演示说明 3.操作方法如何 <script src="../js/layer/layer.js" ...

  3. FreeSWITCH小结:关于sip的UDP、TCP与MTU

    1.关于SIP的UDP与MTU的关系 如果sip消息的大小超过了MTU,则有可能被网络中的某一节点分片,而UDP处理分片会有很大的问题,从而导致sip消息传输失败.要解决该问题的话,两种方案: 1)减 ...

  4. Cocos2d-x 3.1.1 Lua演示样例 ActionsProgressTest(进度条)

    Cocos2d-x 3.1.1 Lua演示样例 ActionsProgressTest(进度条) 本篇博客介绍Cocos2d-x中的进度条动画,进度条涉及以下几个重要的类和方法,笔者来给大家具体解说一 ...

  5. NIO - Selector源码分析

    1. 背景 SelectableChannel对象的多路复用器. 可以通过调用Selector.open()方法创建Selector对象.Selector.open()方法会利用系统默认的Select ...

  6. TLS线程局部存储

    0x01 TLS (Thread Local Storage) 为线程单独提供的私有空间 0x02 gcc中的隐式TLS使用方法 隐式TLS __thread int number; 显式TLS pt ...

  7. mysql 一些常用指令

    登陆: mysql -u root -p //登陆,输入root密码 退出登陆 mysql>exit; mysql 为所有ip授权 mysql> GRANT ALL PRIVILEGES ...

  8. nginx vhosts rewrite 独立文件的方式出现

    [root@web01 /]# cat /app/server/nginx/conf/nginx.conf user www www; worker_processes ; error_log /ap ...

  9. FileStream常用的属性和方法 (转)

    对流进行操作时要引用 using System.IO; 命名空间 FileStream常用的属性和方法: 属性: CanRead 判断当前流是否支持读取,返回bool值,True表示可以读取 CanW ...

  10. vs2010 MSDN文档安装方法

    vs2010的MSDN是不能独立安装,必须安装VS2010后才能安装. 安装方法: 1.vs2010的ISO光盘文件中,里面会有个ProductDocumentation文件夹,其实这个就是安装MSD ...