博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用Spring Session和Redis解决分布式Session跨域共享问题
阅读量:7129 次
发布时间:2019-06-28

本文共 5758 字,大约阅读时间需要 19 分钟。

大家可以关注一下公众号“Java架构师秘籍

前言

对于分布式使用Nginx+Tomcat实现负载均衡,最常用的均衡算法有IP_Hash、轮训、根据权重、随机等。不管对于哪一种负载均衡算法,由于Nginx对不同的请求分发到某一个Tomcat,Tomcat在运行的时候分别是不同的容器里,因此会出现session不同步或者丢失的问题。

文末分享了我一部分私人收藏 有兴趣的可以收藏看一下的 都是架构师进阶的内容

实际上实现Session共享的方案很多,其中一种常用的就是使用Tomcat、Jetty等服务器提供的Session共享功能,将Session的内容统一存储在一个数据库(如MySQL)或缓存(如Redis)中。 如何使用 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的管理机制:

不过使用过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使用

官方地址:

官方文档地址:

Spring Session提供了一套创建和管理Servlet HttpSession的方案。Spring Session提供了集群Session(Clustered Sessions)功能,默认采用外置的Redis来存储Session数据,以此来解决Session共享的问题。

一、特性

Spring Session提供以下特性:

API和用于管理用户会话的实现;

HttpSession - 允许以应用程序容器(即Tomcat)中性的方式替换HttpSession;
Clustered Sessions - Spring Session让支持集群会话变得不那么繁琐,并且不和应用程序容器金习性绑定到。
Multiple Browser Sessions - Spring会话支持在单个浏览器实例中管理多个用户的会话。
RESTful APIs - Spring Session允许在headers 中提供会话ID以使用RESTful API。

二、基于XML配置方式的Spring Session案例实现

基于SSM框架的一个小案例,Git OS项目代码地址:

项目展示:

(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"/>

查看源代码可以看到,默认的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>
(4)关于Error creating bean with name ‘enableRedisKeyspaceNotificationsInitializer’错误的处理:

添加如下配置让Spring Session不再执行config命令

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

如果不添加的话,会报如下错误:

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
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)测试

访问链接:

使用工具查看Redis内容:

可以发现已经有值了!并且有expirations,可以看到箭头指向的位置,是失效的时间记录值!

(8)到此,Spring Session的使用已经完成!其他具体的细节请参考: 项目源代码。

总结:

对于分布式环境Session跨域共享的问题,不管是使用开源的框架还是使用自己开发的框架,都需要明白的一个问题是:在Tomcat容器中创建Session是一个很耗费内存的事情。因此,我们在自己写类似框架的时候,我们一定要注意的是,并不是Tomcat为我们创建好了Session之后,我们首先获取Session然后再上传到Redis等进行存储,而是直接有我们自己创建Session,这一点是至关重要的!
欢迎工作一到五年的Java工程师朋友们加入Java架构开发:189288929
本群提供免费的学习指导 架构资料 以及免费的解答

不懂得问题都可以在本群提出来 之后还会有职业生涯规划以及面试指导

额外分享一些自己的收藏:
高可用集群架构技术进阶篇手把手教你玩转Nginx与Docker
链接: 密码: yp8e
走向架构师,你必须了解的Java虚拟机高级特性
链接: 密码: iayw
高并发处理技术老司机带你玩RabbitMq实现性能倍增
链接: 密码: y3sa
2018.07.09-T5架构师带你解读Spring源码~手写SpringMVC实战
链接: 密码: 6amk

转载于:https://blog.51cto.com/13792737/2155953

你可能感兴趣的文章
如何在ChemDraw中输入℃温度符号
查看>>
SSH-Struts第二弹:一个Form提交两个Action
查看>>
词法分析
查看>>
Linux命令(二)
查看>>
Web登录验证之 Shiro
查看>>
LeeCode-Sort Colors
查看>>
Snort2.9.2.3 Installation on CentOS 6.2
查看>>
我的友情链接
查看>>
给软件工程师的自学建议
查看>>
Linux下SVN的备份方式
查看>>
hadoop 3.0.0 alpha1 分布式搭建
查看>>
刘宇凡:从吃饭中的道理领悟SEO
查看>>
1.1办公软件概述
查看>>
python中http的一些编码转换
查看>>
5.继续看W3C的 bootstrap
查看>>
PHP中include和require
查看>>
第一次标题
查看>>
H3C ospf router id 重复真的不能建立邻居吗?
查看>>
【symfoware OPEN】数据库基本操作
查看>>
iphone:截屏
查看>>