大话 Spring Session 共享
javaweb中我们项目稍微正规点,都会用到单点登录这个技术。实现它的方法各家有各界的看法。这几天由于公司项目需求正在研究。下面整理一下最近整理的心得。
简介
- 在分布式项目中另我们头疼的是多项目之间的数据共享(即Session共享),经常会出现数据丢失的情况。为了解决这种Bug。前人已经把我们实现了两种解决的办法。今天我在这里一下这两种方式。侧重偏向第二种方法
配tomcat实现session共享
资源下载
配置Tomcat
下载好上面的jar包,把他放在tomcat的lib文件下。
然后修改Tomcat里的conf/context.xml文件
<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
host="192.168.1.130"
port="7006"
database="db0"
maxInactiveInterval="60" />
上面配置的host和port就是我们redis的host和port,所以在此之前我们需要先开启一个redis服务出来。
点我查看如何配置redis(本文配置集群,配置单节点一样)
点我查看如何配置redis和spring的整合
点我查看如何配置redis中你遇到的问题汇总database就是讲该tomcat与浏览器会话时产生的session存放在redis中的位置
- maxInactiveInterval 就是设置缓存的过期时间。但是在实际测试中我发现这个属性并没有发生作用。(你有啥见解欢迎点评)
到这里我们的第一个Tomcat配置完成。下面就是重复上面的步骤多配制几个Tomcat
配置nginx
- nginx功能丰富,可以作为HTTP服务器,也可以作为反向代理的服务器,邮件服务器。支持FastCGI、SSL、Virtual Host、URL Rewrite、Gzip等功能。并且支持很多第三方的模块扩展。
nginx的下载官网有现成的,直接下载符合自己电脑的版本傻瓜式安装就行了。(安装或者解压不要出现中文)
找到conf/nginx.conf文件在里面修改设置
- listen 802: 我们监听的端口
- server_name 192.168.1.130:监听的地址
- proxy_pass http://mynginxserver:根据情况跳转最后的连接
- 在mynginxserver配置多个Tomcat:
upstream mynginxserver {
server 192.168.1.78:8080 weight=1;
server 192.168.1.130:8080 weight=1;
}
- 完成配置
upstream mynginxserver {
server 192.168.1.78:8080 weight=1;
server 192.168.1.130:8080 weight=1;
}
server {
listen 802;
server_name 192.168.1.130;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://mynginxserver;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
- 这个时候当我们两个Tomcat都在运行状态我们浏览器中输入
192.168.1.130:802
- nginx就会随机选择一个Tomcat来运行了。同时这两个Tomcat的session是共享的。就是说A Tomcat的session B 可以用。就算A 宕机了B也照样按到A的session。
配spring session实现session共享
- 上面的一种方式我也是在网上案列操作的。在自己的项目中并不适合。因为我的项目中配置的是redis集群(非sentinel).所以在Tomcat里面配置是不行的。
解释:第一种方式配置的redis默认是单节点的redis。也就是我们的session会产生sessionID作为redis中key存在我们配置redis节点的库上面。但是如果我们是redis集群的话,集群会将根据key值算出slot值,在根据slot值决定存取在哪一台redis服务商。也就是说在存session前我们根本不知道会存在哪一台redis上。所以这种方法不适合于redis集群。
具体看看我画的思维导图吧:
第二章明显出错了,事实上并没有存储在实现约定的redis上
spring session 配置
- 说了这么多了,我们下面开始讲解spring中集成的session共享配置。首先如果你是maven项目那么直接引入jar
<dependency> <groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.1.1.RELEASE</version>
</dependency>
- 若果你不是maven项目,那么就麻烦你自己去下载这些相关的jar包。
spring-data-redis.jar
redis.clients.jar
spring-session.jar
- 同样这里你需要一下几篇文章来配置redis集群
点我查看如何配置redis
点我查看如何配置redis和spring的整合
点我查看如何配置redis中你遇到的问题汇总
spring配置文件配置
有了上面的准备资料后,我们可以在是spring的配置文件中配置spring session了
很简单我们需要引入spring session中的bean
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
- 在spring的配置文件中我们只需要配置这一个bean就可以了。下面离将session共享到redis集群上只差一步了。就是在web.xml文件中配置拦截器
<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>
</filter-mapping>
- 到这里配置完成了,我们可以重启我们的项目运行一下存取session的部分。然后再去redis集群找看看有没有session。在redis中默认的session的key是
spring:session:sessions:c0d1fadd-b04a-4244-9525-0f13ea7173bf。其中后面一串id就是我们Tomcat和浏览器会话时差生的sessionid。
问题
在上面我们配置spring session 已经可以实现了session共享了。但是细心的朋友可以发现。session并没有真正意义上的共享。上面我们可以看到session在redis集群中的key包含了Tomcat和浏览器的sessionid。也就是说redis上这个session只能是我的这个Tomcat在该浏览器上才可以访问到。别的Tomcat就算和同一个浏览器交互也是拿不到redis上这个session的。这种效果是你们想要的吗。答案并不是。上面实现的效果我用一幅图描述一下。
也就是说上面我的配置只是将Tomcat的session转移到了redis上。多服务的session仍然是各区各的。这是一个大坑。坑了好久。然后我想了另外一种办法现在可以解决这个局限性。
解决办法
- 解决上面的问题。这里我提供三种思路。三种思路我都实现了一下。各有利弊。最后决定采用第三种比较靠谱。
1– 重写spring session源码,重写里面讲session存储在redis那部分代码,主要就是为了将redis 中session的key写成固定值。以后我们在去session中取这个固定的key就可以实现session共享了。
2–只重写spring session中我们的session仓库中去的策略,就是在A项目登录后将产生的sessionID传递给B项目。B项目在根据这个sessionid去redis中获取。
上面两中方法需要自定义很多类,整理了自定义的类和配置文件的配置。点我下载
3– 在向session中存值的地方,将sessionid作为value,请求头中的Host和Agent组合最为key存储在redis上。然后我们在spring session去session的方法里在根据Host和Agent组成的key去获取sessionid,然后就可以获取对应的session了。
存取策略重构
- 这里主要讲解一下第三种的实现步骤。首先我新建一个类用来读取request求情头中的host和agent拼接的key值。
public static Map<String, Object> getInfoFromUrl(HttpServletRequest request)
{
Map<String, Object> resultMap=new HashMap<String, Object>();
String Agent = request.getHeader("User-Agent");
String Host = request.getHeader("Host");
resultMap.put("agent", Agent);
resultMap.put("host", Host);
return resultMap;
}
public static String getKeyFromUrl(HttpServletRequest request)
{
String result="";
Map<String, Object> map = getInfoFromUrl(request);
Set<String> keySet = map.keySet();
for (String key : keySet)
{
result+=map.get(key).toString();
}
return result;
}
- 然后在我们调用session存值的地方,也就是登录的地方。通过我们项目中的redis操作类将其存储起来。
- 然后我们修改spring session中的cookie仓库中的去request的sessionid的策略
- 最后我们在spring的配置中修改是spring session的策略为我么你的cook策略
<bean id="redisCacheTemplate" class="com.bshinfo.web.base.cache.RedisCacheTemplate"/>
<bean id="zxh" class="com.bshinfo.web.base.cache.CookieHttpSessionStrategyTest">
<property name="redisCacheTemplate" ref="redisCacheTemplate" />
</bean>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<property name="httpSessionStrategy" ref="zxh"/>
<property name="maxInactiveIntervalInSeconds" value="60"/>
</bean>
- 最后就实现了我们的效果。效果就是A项目在X浏览器上登录后。B项目在X浏览器获取session的用户可以正常获取。否则获取失败。
大话 Spring Session 共享的更多相关文章
- Spring session共享(使用redis)
SpringBoot+Redis实现HttpSession共享 前提:需要使用redis做session存储 一.效果演练(这里使用SpringBoot工程,Spring同理) 1.一个工程使用两个端 ...
- 基于Spring Boot/Spring Session/Redis的分布式Session共享解决方案
分布式Web网站一般都会碰到集群session共享问题,之前也做过一些Spring3的项目,当时解决这个问题做过两种方案,一是利用nginx,session交给nginx控制,但是这个需要额外工作较多 ...
- [Spring] spring-session + JedisPool 实现 session 共享
1.至少导入四个jar包: jedis spring-session spring-data-redis commons-pool2 2.bean配置 <?xml version="1 ...
- 单点登录实现(spring session+redis完成session共享)
一.前言 项目中用到的SSO,使用开源框架cas做的.简单的了解了一下cas,并学习了一下 单点登录的原理,有兴趣的同学也可以学习一下,写个demo玩一玩. 二.工程结构 我模拟了 sso的客户端和s ...
- XML配置spring session jdbc实现session共享
概述 session的基础知识就不再多说. 通常,我们会把一个项目部署到多个tomcat上,通过nginx进行负载均衡,提高系统的并发性.此时,就会存在一个问题.假如用户第一次访问tomcat1,并登 ...
- Nginx+Tomcat搭建集群,Spring Session+Redis实现Session共享
小伙伴们好久不见!最近略忙,博客写的有点少,嗯,要加把劲.OK,今天给大家带来一个JavaWeb中常用的架构搭建,即Nginx+Tomcat搭建服务集群,然后通过Spring Session+Redi ...
- Spring Boot(十一)Redis集成从Docker安装到分布式Session共享
一.简介 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API,Redis也是技术领域使用最为广泛的存储中间件,它是 ...
- Spring boot集成spring session实现session共享
最近使用spring boot开发一个系统,nginx做负载均衡分发请求到多个tomcat,此时访问页面会把请求分发到不同的服务器,session是存在服务器端,如果首次访问被分发到A服务器,那么se ...
- spring boot集成redis实现session共享
1.pom文件依赖 <!--spring boot 与redis应用基本环境配置 --> <dependency> <groupId>org.springframe ...
随机推荐
- 【无线安全实践入门】网络扫描和ARP欺骗
文中可能存在错误操作或错误理解,望大家不吝指正. 同时也希望可以帮助到想要学习接触此方面.或兴趣使然的你,让你有个大概的印象. !阅前须知! 本文是基于我几年前的一本笔记本,上面记录了我学习网络基础时 ...
- synchronized与ReentrantLock实现共享资源的消费
主方法 public class synchronizedTest { public static void main(String[] args) { long startTime = System ...
- 微信小程序 键盘显示短信验证码
1.场景描述: IOS系统 一些APP或者微信小程序在收到短信验证码的时候会在键盘上自动保存验证码信息,当用户点击的时候,会自动赋值到当前所点击的输入框中 2.案例: 2.实现: TIPS:这个功能是 ...
- 剑指offer第二版-6.从尾到头打印链表
描述:输入一个链表的头节点,从尾到头打印每个节点的值. 思路:从尾到头打印,即为“先进后出”,则可以使用栈来处理:考虑递归的本质也是一个栈结构,可递归输出. 考点:对链表.栈.递归的理解. packa ...
- Bzoj 1229: [USACO2008 Nov]toy 玩具 题解 三分+贪心
1229: [USACO2008 Nov]toy 玩具 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 338 Solved: 136[Submit] ...
- 个人永久性免费-Excel催化剂功能第94波-地图数据挖宝之搜索地图上的各种兴趣点数据(商铺名、地名、公共设施等)
终于来到最激动人心的地图应用场景,将地图上的有价值的兴趣点数据一网打尽,全都收录在自己的数据源中,这个价值有多大,想想都兴奋,无数的商业场景可供挖掘,假如你还无动于衷,那要好好反思下自己做的数据分析的 ...
- 【带着canvas去流浪(13)】用Three.js制作简易的MARVEL片头动画(下)
目录 一. 模型的制作 1.1 生成字体模型 1.2 多表面贴图 二. 镜头及动画 三. 大作业总结 示例代码托管在:http://www.github.com/dashnowords/blogs 博 ...
- IT界的复仇者联盟解读
漫威宇宙应用到IT界也是可以解读的,自从编程语言分了派系后,故事就多了,今天我们就用漫威宇宙的故事来解读一下IT界的故事. 漫威宇宙其实也就讲了一件事,整个宇宙就好比一个Java项目,其中有一群叫做美 ...
- 转 java - 如何判断单链表有环
转自 https://blog.csdn.net/u010983881/article/details/78896293 1.穷举遍历 首先从头节点开始,依次遍历单链表的每一个节点.每遍历到一个新节点 ...
- javaScript操作DOM深入理解
做为一个web前端,处理和了解浏览器差异一个重要问题.下面将介绍本人在工作中的一些笔记总结,先介绍没有使用js库的情况. 1. setAttribute方法设置元素类名 : 在jQuery中,直接使用 ...